Compare commits

...
59 Commits
Author SHA1 Message Date
steve e67952240b Installation fixes for Debian. 1999-12-03 17:43:49 +00:00
steve 22d89c5984 Update case comparison (Eric Aardoom). 1999-12-02 16:58:58 +00:00
steve 88193a369f Handle mux sel of X, if inputs are equal. 1999-12-02 04:54:11 +00:00
steve cdb99e7638 Elaborate net repeat concatenations. 1999-12-02 04:08:10 +00:00
steve 99e145da48 shiftl and shiftr take unsized second parameter. 1999-12-02 03:36:01 +00:00
steve b30b695ff0 Redo synth to use match_proc_t scanner. 1999-12-01 06:06:16 +00:00
steve 998c039fd9 Match scope names as last resort. 1999-11-30 04:54:01 +00:00
steve 5ffac8adbf Handle evaluation of ternary during elaboration. 1999-11-30 04:48:17 +00:00
steve 80b8ea95bb Put implicitly defined signals in the scope. 1999-11-30 04:33:41 +00:00
steve 68a7ce3745 include getopt if present. 1999-11-29 17:02:21 +00:00
steve bb68753bd2 Properly initialize registers. 1999-11-29 00:38:27 +00:00
steve dab47610ed Remove useless tests for NetESignal. 1999-11-28 23:59:22 +00:00
steve e96e8c62be NetESignal object no longer need to be NetNode
objects. Let them keep a pointer to NetNet objects.
1999-11-28 23:42:02 +00:00
steve fa088f8baa Set VPI_MODULE_PATH in the target code, if desired. 1999-11-28 18:05:37 +00:00
steve 48b6726cf4 gate outputs need to set signal values. 1999-11-28 01:16:18 +00:00
steve bf42be12de Build up the lists in the scope of a module,
and get $dumpvars to scan the scope for items.
1999-11-28 00:56:08 +00:00
steve 4cfa3e4047 Support the creation of scopes. 1999-11-27 19:07:57 +00:00
steve ac25dc03a8 Reduce more gate templates to use vvm_1bit_out (Eric Aardoom) 1999-11-25 01:34:04 +00:00
steve 680c35a845 LT and GT fixes from Eric Aardoom. 1999-11-24 04:38:49 +00:00
steve 26288eeeb4 Detect and list scope names. 1999-11-24 04:01:58 +00:00
steve 3a69ab8934 support line directives with the line keyword. 1999-11-23 02:49:04 +00:00
steve cd3ed1959e A file name of - means standard input. 1999-11-23 01:04:57 +00:00
steve eb72a83e5f Detemplate some and, or and nor methods. 1999-11-22 00:30:52 +00:00
steve 85ab6d160b Handle multiply in constant expressions. 1999-11-21 20:03:24 +00:00
steve b769c7781e no -fno-exceptions to the C compiler. 1999-11-21 20:02:37 +00:00
steve 7324673bd1 Fix expression width of memory references. 1999-11-21 18:03:35 +00:00
steve 4cfa715092 Memory name lookup handles scopes. 1999-11-21 17:35:37 +00:00
steve b4aade1e4c Fix coding errors handling names of logic devices,
and add support for buf device in vvm.
1999-11-21 01:16:51 +00:00
steve a81dcd7955 Support memories in continuous assignments. 1999-11-21 00:13:08 +00:00
steve fae40cf380 handle duplicate connect to a nexus. 1999-11-19 05:02:37 +00:00
steve 28149e73e3 Handle inverted clock into OUTFF. 1999-11-19 05:02:15 +00:00
steve 8b81d6e416 Detect flip-flops connected to opads and turn
them into OUTFF devices. Inprove support for
 the XNF-LCA attribute in the process.
1999-11-19 03:02:25 +00:00
steve fbf0bf1fb7 Whoops, created a signal with a duplicate name. 1999-11-19 03:00:59 +00:00
steve 9d6392fda9 Turn NetTmp objects into normal local NetNet objects,
and add the nodangle functor to clean up the local
 symbols generated by elaboration and other steps.
1999-11-18 03:52:19 +00:00
steve 23ce3a9042 Handle (with a warning) unconnected opads. 1999-11-18 02:58:37 +00:00
steve 33946e188c Add algorithm for choosing nexus name from attached signals. 1999-11-17 18:52:09 +00:00
steve 477495c648 Clean up warnings that add_sub got from Alliance 1999-11-17 01:31:28 +00:00
steve 16f7268729 notice d and D in numbers. 1999-11-17 00:50:06 +00:00
steve a4a0ba670d Allow qualified identifiers. They really do work. 1999-11-15 04:43:52 +00:00
steve e98083af15 Fixup to include right shift support. 1999-11-15 00:42:31 +00:00
steve 513ade9b95 Support combinatorial comparators. 1999-11-14 23:43:45 +00:00
steve 1624afe1ba Add support for the LPM_CLSHIFT device. 1999-11-14 20:24:28 +00:00
steve 0eb6056ea6 Fix NAND gate support to use named pins. 1999-11-14 18:22:12 +00:00
steve 2602505885 Support the LPM_MUX in vvm. 1999-11-13 03:46:52 +00:00
steve 82f3f0f741 Create the vpiMemory handle type. 1999-11-10 02:52:24 +00:00
steve 02f8099aa7 Add VCD output and related system tasks. 1999-11-07 20:33:30 +00:00
steve 43ff33cd79 Add the $monitor implementation. 1999-11-07 02:25:07 +00:00
steve 2d1ace1dbc Unify display and strobe format routines. 1999-11-06 23:32:14 +00:00
steve 8d806d538b Get the $strobe task working. 1999-11-06 22:16:50 +00:00
steve 3fe0344246 complete value retrieval for number constants. 1999-11-06 16:52:16 +00:00
steve c688d95cb8 Put number constants into a static table. 1999-11-06 16:00:17 +00:00
steve 282c58040b Support writing some XNF things into an NCF file. 1999-11-06 04:51:42 +00:00
steve c18ea61994 Catch NetTmp objects. 1999-11-06 04:51:11 +00:00
steve 5171846d72 Forgot to return the mux for use after elaboration. 1999-11-05 23:36:31 +00:00
steve 206b37e5de Fix NetConst being set to zero width, and clean
up elaborate_set_cmp_ for NetEBinary.
1999-11-05 21:45:19 +00:00
steve f7526c6c4b parse drive strengths. 1999-11-05 19:36:36 +00:00
steve f827ad8625 fix syntax of EQN record. 1999-11-05 18:43:12 +00:00
steve 93a1f4853b Include the obvious XOR gates in the adders. 1999-11-05 07:10:45 +00:00
steve 2cce0ce238 Patch to synthesize LPM_ADD_SUB from expressions,
Thanks to Larry Doolittle. Also handle constants
 in expressions.

 Synthesize adders in XNF, based on a patch from
 Larry. Accept synthesis of constants from Larry
 as is.
1999-11-05 04:40:40 +00:00
56 changed files with 4985 additions and 1878 deletions
+8 -8
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.27 1999/11/02 04:55:34 steve Exp $"
#ident "$Id: Makefile.in,v 1.24.2.1 1999/12/03 17:43:49 steve Exp $"
#
#
SHELL = /bin/sh
@@ -66,10 +66,10 @@ distclean: clean
rm -f Makefile
TT = t-null.o t-verilog.o t-vvm.o t-xnf.o
FF = nobufz.o propinit.o sigfold.o synth.o xnfio.o xnfsyn.o
FF = nobufz.o propinit.o sigfold.o xnfio.o xnfsyn.o
O = main.o cprop.o design_dump.o elaborate.o elab_expr.o elab_net.o \
emit.o eval.o eval_tree.o expr_synth.o functor.o \
O = main.o cprop.o design_dump.o elaborate.o elab_expr.o emit.o eval.o \
eval_tree.o functor.o \
lexor.o lexor_keyword.o mangle.o netlist.o pad_to_width.o \
parse.o parse_misc.o pform.o pform_dump.o \
set_width.o \
@@ -113,7 +113,7 @@ parse.h parse.cc: $(srcdir)/parse.y
lexor.cc: $(srcdir)/lexor.lex
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
install: all installdirs $(bindir)/verilog $(bindir)/ivl $(mandir)/man1/verilog.1
install: all installdirs $(bindir)/verilog $(libdir)/ivl/ivl $(mandir)/man1/verilog.1
cd vpi ; $(MAKE) install
cd vvm ; $(MAKE) install
cd ivlpp ; $(MAKE) install
@@ -121,9 +121,9 @@ install: all installdirs $(bindir)/verilog $(bindir)/ivl $(mandir)/man1/verilog.
$(bindir)/verilog: ./verilog
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
$(bindir)/ivl: ivl
$(INSTALL_PROGRAM) ./ivl $(bindir)/ivl
$(STRIP) $(bindir)/ivl
$(libdir)/ivl/ivl: ivl
$(INSTALL_PROGRAM) ./ivl $(libdir)/ivl/ivl
$(STRIP) $(libdir)/ivl/ivl
$(mandir)/man1/verilog.1: $(srcdir)/verilog.1
$(INSTALL_DATA) $(srcdir)/verilog.1 $(mandir)/man1/verilog.1
+6 -2
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: Module.h,v 1.9 1999/08/23 16:48:39 steve Exp $"
#ident "$Id: Module.h,v 1.10 1999/11/27 19:07:57 steve Exp $"
#endif
# include <list>
@@ -33,6 +33,7 @@ class PFunction;
class PWire;
class PProcess;
class Design;
class NetScope;
/*
* A module is a named container and scope. A module holds a bunch of
@@ -93,7 +94,7 @@ class Module {
const list<PProcess*>& get_behaviors() const { return behaviors_; }
void dump(ostream&out) const;
bool elaborate(Design*, const string&path, svector<PExpr*>*overrides_) const;
bool elaborate(Design*, NetScope*scope, svector<PExpr*>*overrides_) const;
private:
const string name_;
@@ -113,6 +114,9 @@ class Module {
/*
* $Log: Module.h,v $
* Revision 1.10 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.9 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
+27 -1
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PExpr.h,v 1.22 1999/10/31 20:08:24 steve Exp $"
#ident "$Id: PExpr.h,v 1.25 1999/11/21 00:13:08 steve Exp $"
#endif
# include <string>
@@ -159,6 +159,12 @@ class PEIdent : public PExpr {
// If this is a reference to a memory, this is the index
// expression.
PExpr*idx_;
NetNet* elaborate_net_ram_(Design*des, const string&path,
NetMemory*mem, unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
};
class PENumber : public PExpr {
@@ -248,6 +254,16 @@ class PEBinary : public PExpr {
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_cmp_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_shift_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
};
/*
@@ -297,6 +313,16 @@ class PECallFunction : public PExpr {
/*
* $Log: PExpr.h,v $
* Revision 1.25 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.24 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.23 1999/11/05 21:45:19 steve
* Fix NetConst being set to zero width, and clean
* up elaborate_set_cmp_ for NetEBinary.
*
* Revision 1.22 1999/10/31 20:08:24 steve
* Include subtraction in LPM_ADD_SUB device.
*
+5 -2
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PWire.h,v 1.5 1999/06/17 05:34:42 steve Exp $"
#ident "$Id: PWire.h,v 1.6 1999/11/27 19:07:57 steve Exp $"
#endif
# include "netlist.h"
@@ -58,7 +58,7 @@ class PWire : public LineInfo {
// Write myself to the specified stream.
void dump(ostream&out) const;
void elaborate(Design*, const string&path) const;
void elaborate(Design*, NetScope*scope) const;
private:
string name_;
@@ -82,6 +82,9 @@ class PWire : public LineInfo {
/*
* $Log: PWire.h,v $
* Revision 1.6 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.5 1999/06/17 05:34:42 steve
* Clean up interface of the PWire class,
* Properly match wire ranges.
+2
View File
@@ -327,6 +327,8 @@ current state of support for Verilog.
reg [7:0] del;
always #(reg) $display($time,,"del = %d", del); // sorry
- drive strengths are parsed, bug ignored.
Specify blocks are parsed but ignored in general.
+1
View File
@@ -5,6 +5,7 @@ dnl Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_CHECK_TOOL(STRIP, strip, true)
AC_CHECK_HEADERS(getopt.h)
AC_PROG_INSTALL
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
+76 -9
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: design_dump.cc,v 1.55 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: design_dump.cc,v 1.61 1999/11/28 23:42:02 steve Exp $"
#endif
/*
@@ -49,6 +49,8 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
pin_count() << "]";
if (local_flag_)
o << " (local)";
if (scope_)
o << " scope=" << scope_->name();
o << " #(" << rise_time() << "," << fall_time() << "," <<
decay_time() << ") init=";
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
@@ -130,6 +132,22 @@ void NetAddSub::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetCLShift::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Combinatorial shift (NetCLShift): " <<
name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetCompare::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " <<
name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetMux::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Multiplexer (NetMux): " << name() << endl;
@@ -225,6 +243,14 @@ void NetLogic::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetRamDq::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_RAM_DQ (" << mem_->name() << "): "
<< name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetTaskDef::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "task " << name_ << ";" << endl;
@@ -555,6 +581,23 @@ void NetRepeat::dump(ostream&o, unsigned ind) const
statement_->dump(o, ind+2);
}
void NetScope::dump(ostream&o) const
{
o << name_;
switch (type_) {
case BEGIN_END:
o << " sequential block";
break;
case FORK_JOIN:
o << " parallel block";
break;
case MODULE:
o << " module";
break;
}
o << endl;
}
void NetSTask::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << name_;
@@ -681,6 +724,11 @@ void NetEIdent::dump(ostream&o) const
o << name_;
}
void NetEScope::dump(ostream&o) const
{
o << "<scope=" << scope_->name() << ">";
}
void NetESignal::dump(ostream&o) const
{
o << name();
@@ -706,14 +754,6 @@ void NetEParam::dump(ostream&o) const
o << "<" << path_ << "." << name_ << ">";
}
void NetESignal::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Expression Node (NetESignal): " <<
name() << endl;
dump_node_pins(o, ind+4);
}
void NetETernary::dump(ostream&o) const
{
o << "(" << *cond_ << ") ? (" << *true_val_ << ") : (" <<
@@ -749,6 +789,14 @@ void NetEUnary::dump(ostream&o) const
void Design::dump(ostream&o) const
{
o << "SCOPES:" << endl;
{
map<string,NetScope*>::const_iterator pp;
for (pp = scopes_.begin()
; pp != scopes_.end() ; pp ++)
(*pp).second -> dump(o);
}
o << "ELABORATED PARAMETERS:" << endl;
{
map<string,NetExpr*>::const_iterator pp;
@@ -818,6 +866,25 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.61 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.60 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.59 1999/11/24 04:01:58 steve
* Detect and list scope names.
*
* Revision 1.58 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.57 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.56 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.55 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* 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)
#ident "$Id: dup_expr.cc,v 1.1 1999/11/27 19:07:57 steve Exp $"
#endif
# include "netlist.h"
# include <cassert>
NetEScope* NetEScope::dup_expr() const
{
assert(0);
return 0;
}
/*
* $Log: dup_expr.cc,v $
* Revision 1.1 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
*/
+36 -12
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: elab_expr.cc,v 1.7 1999/10/18 00:02:21 steve Exp $"
#ident "$Id: elab_expr.cc,v 1.12 1999/11/30 04:54:01 steve Exp $"
#endif
@@ -154,7 +154,6 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
assert(res);
NetESignal*eres = new NetESignal(res);
assert(eres);
des->add_node(eres);
NetEUFunc*func = new NetEUFunc(def, eres, parms);
return func;
}
@@ -209,15 +208,17 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
assert(net->sb_to_idx(msv) >= net->sb_to_idx(lsv));
string tname = des->local_symbol(path);
NetESignal*tmp = new NetESignal(tname, wid);
tmp->set_line(*this);
NetTmp*tsig = new NetTmp(tname, wid);
// Connect the pins from the lsb up to the msb.
unsigned off = net->sb_to_idx(lsv);
for (unsigned idx = 0 ; idx < wid ; idx += 1)
connect(tmp->pin(idx), net->pin(idx+off));
connect(tsig->pin(idx), net->pin(idx+off));
des->add_node(tmp);
NetESignal*tmp = new NetESignal(tsig);
tmp->set_line(*this);
des->add_signal(tsig);
return tmp;
}
@@ -230,16 +231,16 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
unsigned long msv = msn->as_ulong();
string tname = des->local_symbol(path);
NetESignal*tmp = new NetESignal(tname, 1);
NetTmp*tsig = new NetTmp(tname);
connect(tsig->pin(0), net->pin(msv));
NetESignal*tmp = new NetESignal(tsig);
tmp->set_line(*this);
connect(tmp->pin(0), net->pin(msv));
des->add_node(tmp);
des->add_signal(tsig);
return tmp;
}
NetESignal*node = new NetESignal(net);
des->add_node(node);
assert(idx_ == 0);
// Non-constant bit select? punt and make a subsignal
@@ -260,7 +261,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
// If the identifier names a memory, then this is a
// memory reference and I must generate a NetEMemory
// object to handle it.
if (NetMemory*mem = des->find_memory(name)) {
if (NetMemory*mem = des->find_memory(path, text_)) {
if (msb_ == 0) {
cerr << get_line() << ": error: Memory ``" << name <<
"'' referenced without an index expression." << endl;
@@ -271,7 +272,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
assert(lsb_ == 0);
assert(idx_ == 0);
NetExpr*i = msb_->elaborate_expr(des, path);
if (i == 0) {
if (msb_ && i == 0) {
cerr << get_line() << ": error: Unable to exaborate "
"index expression `" << *msb_ << "'" << endl;
des->errors += 1;
@@ -283,6 +284,13 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
return node;
}
// Finally, if this is a scope name, then return that.
if (NetScope*nsc = des->find_scope(text_)) {
NetEScope*tmp = new NetEScope(nsc);
tmp->set_line(*this);
return tmp;
}
// I cannot interpret this identifier. Error message.
cerr << get_line() << ": error: Unable to bind wire/reg/memory "
"`" << path << "." << text_ << "'" << endl;
@@ -324,6 +332,22 @@ NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const
/*
* $Log: elab_expr.cc,v $
* Revision 1.12 1999/11/30 04:54:01 steve
* Match scope names as last resort.
*
* Revision 1.11 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.10 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.9 1999/11/21 17:35:37 steve
* Memory name lookup handles scopes.
*
* Revision 1.8 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.7 1999/10/18 00:02:21 steve
* Catch unindexed memory reference.
*
+640 -84
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: elab_net.cc,v 1.2 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: elab_net.cc,v 1.11 1999/12/02 04:08:10 steve Exp $"
#endif
# include "PExpr.h"
@@ -38,6 +38,17 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
case '+':
case '-':
return elaborate_net_add_(des, path, width, rise, fall, decay);
case 'E':
case 'e':
case 'n':
case '<':
case '>':
case 'L': // <=
case 'G': // >=
return elaborate_net_cmp_(des, path, width, rise, fall, decay);
case 'l': // <<
case 'r': // >>
return elaborate_net_shift_(des, path, width, rise, fall, decay);
}
NetNet*lsig = left_->elaborate_net(des, path, width, 0, 0, 0),
@@ -62,7 +73,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
switch (op_) {
case '^': // XOR
assert(lsig->pin_count() == rsig->pin_count());
osig = new NetNet(des->local_symbol(path), NetNet::WIRE,
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
@@ -81,7 +92,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
case '&': // AND
assert(lsig->pin_count() == rsig->pin_count());
osig = new NetNet(des->local_symbol(path), NetNet::WIRE,
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
@@ -100,7 +111,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
case '|': // Bitwise OR
assert(lsig->pin_count() == rsig->pin_count());
osig = new NetNet(des->local_symbol(path), NetNet::WIRE,
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
@@ -145,7 +156,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
}
// The output is the AND of the two logic values.
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
osig->local_flag(true);
connect(gate->pin(0), osig->pin(0));
des->add_signal(osig);
@@ -156,81 +167,13 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
break;
case 'E': // === (Case equals)
// The comparison generates gates to bitwise compare
// each pair, and AND all the comparison results.
assert(lsig->pin_count() == rsig->pin_count());
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
osig->local_flag(true);
gate = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(),
NetLogic::AND);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate_t = new NetCaseCmp(des->local_symbol(path));
connect(gate_t->pin(1), lsig->pin(idx));
connect(gate_t->pin(2), rsig->pin(idx));
connect(gate_t->pin(0), gate->pin(idx+1));
des->add_node(gate_t);
// Attach a label to this intermediate wire
NetNet*tmp = new NetNet(des->local_symbol(path),
NetNet::WIRE);
tmp->local_flag(true);
connect(gate_t->pin(0), tmp->pin(0));
des->add_signal(tmp);
}
des->add_signal(osig);
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
break;
case 'e': // ==
assert(lsig->pin_count() == rsig->pin_count());
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
osig->local_flag(true);
gate = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(),
NetLogic::AND);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate_t = new NetLogic(des->local_symbol(path), 3,
NetLogic::XNOR);
connect(gate_t->pin(1), lsig->pin(idx));
connect(gate_t->pin(2), rsig->pin(idx));
connect(gate_t->pin(0), gate->pin(idx+1));
des->add_node(gate_t);
}
des->add_signal(osig);
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
break;
case 'n': // !=
assert(lsig->pin_count() == rsig->pin_count());
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
osig->local_flag(true);
gate = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(),
NetLogic::OR);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate_t = new NetLogic(des->local_symbol(path), 3,
NetLogic::XOR);
connect(gate_t->pin(1), lsig->pin(idx));
connect(gate_t->pin(2), rsig->pin(idx));
connect(gate_t->pin(0), gate->pin(idx+1));
des->add_node(gate_t);
}
des->add_signal(osig);
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
case '<':
case '>':
case 'G': // >=
case 'L': // <=
assert(0);
break;
case '+':
@@ -239,10 +182,7 @@ NetNet* PEBinary::elaborate_net(Design*des, const string&path,
case 'l':
case 'r':
cerr << get_line() << ": sorry: combinational shift"
" not supported here." << endl;
des->errors += 1;
osig = 0;
assert(0);
break;
default:
cerr << get_line() << ": internal error: unsupported"
@@ -297,7 +237,7 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, const string&path,
width = rsig->pin_count();
// Make the adder as wide as the widest operand
osig = new NetNet(des->local_symbol(path), NetNet::WIRE, width);
osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE, width);
NetAddSub*adder = new NetAddSub(name, width);
// Connect the adder to the various parts.
@@ -332,6 +272,589 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, const string&path,
return osig;
}
/*
* Elaborate the various binary comparison operators.
*/
NetNet* PEBinary::elaborate_net_cmp_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0),
*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0);
if (lsig == 0) {
cerr << get_line() << ": error: Cannot elaborate ";
left_->dump(cerr);
cerr << endl;
return 0;
}
if (rsig == 0) {
cerr << get_line() << ": error: Cannot elaborate ";
right_->dump(cerr);
cerr << endl;
return 0;
}
if (lsig->pin_count() != rsig->pin_count()) {
cerr << get_line() << ": internal error: Cannot match "
"structural net widths " << lsig->pin_count() <<
" and " << rsig->pin_count() << "." << endl;
delete lsig;
delete rsig;
des->errors += 1;
return 0;
}
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
osig->local_flag(true);
NetNode*gate;
NetNode*gate_t;
switch (op_) {
case '<':
case '>':
case 'L':
case 'G': {
NetCompare*cmp = new NetCompare(des->local_symbol(path),
lsig->pin_count());
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
connect(cmp->pin_DataA(idx), lsig->pin(idx));
connect(cmp->pin_DataB(idx), rsig->pin(idx));
}
switch (op_) {
case '<':
connect(cmp->pin_ALB(), osig->pin(0));
break;
case '>':
connect(cmp->pin_AGB(), osig->pin(0));
break;
case 'L':
connect(cmp->pin_ALEB(), osig->pin(0));
break;
case 'G':
connect(cmp->pin_AGEB(), osig->pin(0));
break;
}
gate = cmp;
break;
}
case 'E': // Case equals (===)
// The comparison generates gates to bitwise compare
// each pair, and AND all the comparison results.
gate = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(),
NetLogic::AND);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate_t = new NetCaseCmp(des->local_symbol(path));
connect(gate_t->pin(1), lsig->pin(idx));
connect(gate_t->pin(2), rsig->pin(idx));
connect(gate_t->pin(0), gate->pin(idx+1));
des->add_node(gate_t);
// Attach a label to this intermediate wire
NetNet*tmp = new NetNet(0, des->local_symbol(path),
NetNet::WIRE);
tmp->local_flag(true);
connect(gate_t->pin(0), tmp->pin(0));
des->add_signal(tmp);
}
break;
case 'e': // ==
gate = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(),
NetLogic::AND);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate_t = new NetLogic(des->local_symbol(path), 3,
NetLogic::XNOR);
connect(gate_t->pin(1), lsig->pin(idx));
connect(gate_t->pin(2), rsig->pin(idx));
connect(gate_t->pin(0), gate->pin(idx+1));
des->add_node(gate_t);
}
break;
case 'n': // !=
gate = new NetLogic(des->local_symbol(path),
1+lsig->pin_count(),
NetLogic::OR);
connect(gate->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
gate_t = new NetLogic(des->local_symbol(path), 3,
NetLogic::XOR);
connect(gate_t->pin(1), lsig->pin(idx));
connect(gate_t->pin(2), rsig->pin(idx));
connect(gate_t->pin(0), gate->pin(idx+1));
des->add_node(gate_t);
}
break;
default:
assert(0);
}
des->add_signal(osig);
gate->rise_time(rise);
gate->fall_time(fall);
gate->decay_time(decay);
des->add_node(gate);
return osig;
}
NetNet* PEBinary::elaborate_net_shift_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
NetNet*lsig = left_->elaborate_net(des, path, lwidth, 0, 0, 0);
if (lsig == 0) return 0;
/* Handle the special case of a constant shift amount. There
is no reason in this case to create a gate at all, just
connect the lsig to the osig with the bit positions
shifted. */
if (verinum*rval = right_->eval_const(des, path)) {
assert(rval->is_defined());
unsigned dist = rval->as_ulong();
if (dist > lsig->pin_count())
dist = lsig->pin_count();
/* Very special case, constant 0 shift. */
if (dist == 0) return lsig;
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
NetConst*zero = new NetConst(des->local_symbol(path), verinum::V0);
des->add_node(zero);
if (op_ == 'l') {
unsigned idx;
for (idx = 0 ; idx < dist ; idx += 1)
connect(osig->pin(idx), zero->pin(0));
for (idx = dist ; idx < lsig->pin_count() ; idx += 1)
connect(osig->pin(idx), lsig->pin(idx-dist));
} else {
assert(op_ == 'r');
unsigned idx;
unsigned keep = lsig->pin_count()-dist;
for (idx = 0 ; idx < keep ; idx += 1)
connect(osig->pin(idx), lsig->pin(idx+dist));
for (idx = keep ; idx < lsig->pin_count() ; idx += 1)
connect(osig->pin(idx), zero->pin(0));
}
des->add_signal(osig);
return osig;
}
unsigned dwid = 0;
while ((1 << dwid) < lsig->pin_count())
dwid += 1;
NetNet*rsig = right_->elaborate_net(des, path, dwid, 0, 0, 0);
if (rsig == 0) return 0;
NetCLShift*gate = new NetCLShift(des->local_symbol(path),
lsig->pin_count(),
rsig->pin_count());
NetNet*osig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
lsig->pin_count());
osig->local_flag(true);
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
connect(osig->pin(idx), gate->pin_Result(idx));
connect(lsig->pin(idx), gate->pin_Data(idx));
}
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
connect(rsig->pin(idx), gate->pin_Distance(idx));
if (op_ == 'r') {
NetConst*dir = new NetConst(des->local_symbol(path), verinum::V1);
connect(dir->pin(0), gate->pin_Direction());
des->add_node(dir);
}
des->add_signal(osig);
des->add_node(gate);
return osig;
}
/*
* The concatenation operator, as a net, is a wide signal that is
* connected to all the pins of the elaborated expression nets.
*/
NetNet* PEConcat::elaborate_net(Design*des, const string&path,
unsigned,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
svector<NetNet*>nets (parms_.count());
unsigned pins = 0;
unsigned errors = 0;
if (repeat_) {
verinum*rep = repeat_->eval_const(des, path);
if (rep == 0) {
cerr << get_line() << ": internal error: Unable to "
<< "evaluate constant repeat expression." << endl;
des->errors += 1;
return 0;
}
unsigned long repeat = rep->as_ulong();
assert(parms_.count() == 1);
NetNet*obj = parms_[0]->elaborate_net(des, path, 0, rise,
fall, decay);
NetTmp*tmp = new NetTmp(des->local_symbol(path),
repeat * obj->pin_count());
for (unsigned idx = 0 ; idx < repeat ; idx += 1) {
unsigned base = obj->pin_count() * idx;
for (unsigned pin = 0 ; pin < obj->pin_count() ; pin += 1)
connect(tmp->pin(base+pin), obj->pin(pin));
}
des->add_signal(tmp);
return tmp;
}
/* Elaborate the operands of the concatenation. */
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
nets[idx] = parms_[idx]->elaborate_net(des, path, 0,
rise,fall,decay);
if (nets[idx] == 0)
errors += 1;
else
pins += nets[idx]->pin_count();
}
/* If any of the sub expressions failed to elaborate, then
delete all those that did and abort myself. */
if (errors) {
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
if (nets[idx]) delete nets[idx];
}
des->errors += 1;
return 0;
}
/* Make the temporary signal that connects to all the
operands, and connect it up. Scan the operands of the
concat operator from least significant to most significant,
which is opposite from how they are given in the list. */
NetNet*osig = new NetNet(0, des->local_symbol(path),
NetNet::IMPLICIT, pins);
pins = 0;
for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) {
NetNet*cur = nets[idx-1];
for (unsigned pin = 0 ; pin < cur->pin_count() ; pin += 1) {
connect(osig->pin(pins), cur->pin(pin));
pins += 1;
}
}
osig->local_flag(true);
des->add_signal(osig);
return osig;
}
NetNet* PEIdent::elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
NetScope*scope = des->find_scope(path);
NetNet*sig = des->find_signal(path, text_);
if (sig == 0) {
/* If the identifier is a memory instead of a signal,
then handle it elsewhere. Create a RAM. */
if (NetMemory*mem = des->find_memory(path, text_))
return elaborate_net_ram_(des, path, mem, lwidth,
rise, fall, decay);
if (const NetExpr*pe = des->find_parameter(path, text_)) {
const NetEConst*pc = dynamic_cast<const NetEConst*>(pe);
assert(pc);
verinum pvalue = pc->value();
sig = new NetNet(0, path+"."+text_, NetNet::IMPLICIT,
pc->expr_width());
for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) {
NetConst*cp = new NetConst(des->local_symbol(path),
pvalue[idx]);
connect(sig->pin(idx), cp->pin(0));
des->add_node(cp);
}
} else {
sig = new NetNet(scope, path+"."+text_, NetNet::IMPLICIT, 1);
des->add_signal(sig);
cerr << get_line() << ": warning: Implicitly defining "
"wire " << path << "." << text_ << "." << endl;
}
}
assert(sig);
if (msb_ && lsb_) {
verinum*mval = msb_->eval_const(des, path);
if (mval == 0) {
cerr << msb_->get_line() << ": error: unable to "
"evaluate constant expression: " << *msb_ <<
endl;
des->errors += 1;
return 0;
}
verinum*lval = lsb_->eval_const(des, path);
if (lval == 0) {
cerr << lsb_->get_line() << ": error: unable to "
"evaluate constant expression: " << *lsb_ <<
endl;
delete mval;
des->errors += 1;
return 0;
}
assert(mval);
assert(lval);
unsigned midx = sig->sb_to_idx(mval->as_long());
unsigned lidx = sig->sb_to_idx(lval->as_long());
if (midx >= lidx) {
NetTmp*tmp = new NetTmp(des->local_symbol(path),
midx-lidx+1);
des->add_signal(tmp);
if (tmp->pin_count() > sig->pin_count()) {
cerr << get_line() << ": bit select out of "
<< "range for " << sig->name() << endl;
return sig;
}
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
connect(tmp->pin(idx-lidx), sig->pin(idx));
sig = tmp;
} else {
NetTmp*tmp = new NetTmp(des->local_symbol(path),
lidx-midx+1);
des->add_signal(tmp);
assert(tmp->pin_count() <= sig->pin_count());
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
connect(tmp->pin(idx-midx), sig->pin(idx));
sig = tmp;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, path);
if (mval == 0) {
cerr << get_line() << ": index of " << text_ <<
" needs to be constant in this context." <<
endl;
des->errors += 1;
return 0;
}
assert(mval);
unsigned idx = sig->sb_to_idx(mval->as_long());
if (idx >= sig->pin_count()) {
cerr << get_line() << "; index " << sig->name() <<
"[" << mval->as_long() << "] out of range." << endl;
des->errors += 1;
idx = 0;
}
NetTmp*tmp = new NetTmp(des->local_symbol(path), 1);
des->add_signal(tmp);
connect(tmp->pin(0), sig->pin(idx));
sig = tmp;
}
return sig;
}
/*
* When I run into an identifier in an expression that referrs to a
* memory, create a RAM port object.
*/
NetNet* PEIdent::elaborate_net_ram_(Design*des, const string&path,
NetMemory*mem, unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
if (msb_ == 0) {
cerr << get_line() << ": error: memory reference without"
" the required index expression." << endl;
des->errors += 1;
return 0;
}
NetNet*adr = msb_->elaborate_net(des, path, 0, 0, 0, 0);
if (adr == 0)
return 0;
NetRamDq*ram = new NetRamDq(des->local_symbol(mem->name()),
mem, adr->pin_count());
des->add_node(ram);
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
connect(ram->pin_Address(idx), adr->pin(idx));
NetNet*osig = new NetTmp(des->local_symbol(mem->name()), ram->width());
des->add_signal(osig);
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1)
connect(ram->pin_Q(idx), osig->pin(idx));
return osig;
}
/*
* Identifiers in continuous assignment l-values are limited to wires
* and that ilk. Detect registers and memories here and report errors.
*/
NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const
{
NetNet*sig = des->find_signal(path, text_);
if (sig == 0) {
/* Don't allow memories here. Is it a memory? */
if (des->find_memory(path, text_)) {
cerr << get_line() << ": error: memories (" << text_
<< ") cannot be l-values in continuous "
<< "assignments." << endl;
return 0;
}
/* Fine, create an implicit wire as an l-value. */
sig = new NetNet(0, path+"."+text_, NetNet::IMPLICIT, 1);
des->add_signal(sig);
cerr << get_line() << ": warning: Implicitly defining "
"wire " << path << "." << text_ << "." << endl;
}
assert(sig);
/* Don't allow registers as assign l-values. */
if (sig->type() == NetNet::REG) {
cerr << get_line() << ": error: registers (" << sig->name()
<< ") cannot be l-values in continuous"
<< " assignments." << endl;
return 0;
}
if (msb_ && lsb_) {
/* Detect a part select. Evaluate the bits and elaborate
the l-value by creating a sub-net that links to just
the right pins. */
verinum*mval = msb_->eval_const(des, path);
assert(mval);
verinum*lval = lsb_->eval_const(des, path);
assert(lval);
unsigned midx = sig->sb_to_idx(mval->as_long());
unsigned lidx = sig->sb_to_idx(lval->as_long());
if (midx >= lidx) {
NetTmp*tmp = new NetTmp(des->local_symbol(path),
midx-lidx+1);
des->add_signal(tmp);
if (tmp->pin_count() > sig->pin_count()) {
cerr << get_line() << ": bit select out of "
<< "range for " << sig->name() << endl;
return sig;
}
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
connect(tmp->pin(idx-lidx), sig->pin(idx));
sig = tmp;
} else {
NetTmp*tmp = new NetTmp(des->local_symbol(path),
lidx-midx+1);
des->add_signal(tmp);
assert(tmp->pin_count() <= sig->pin_count());
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
connect(tmp->pin(idx-midx), sig->pin(idx));
sig = tmp;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, path);
if (mval == 0) {
cerr << get_line() << ": index of " << text_ <<
" needs to be constant in this context." <<
endl;
des->errors += 1;
return 0;
}
assert(mval);
unsigned idx = sig->sb_to_idx(mval->as_long());
if (idx >= sig->pin_count()) {
cerr << get_line() << "; index " << sig->name() <<
"[" << mval->as_long() << "] out of range." << endl;
des->errors += 1;
idx = 0;
}
NetTmp*tmp = new NetTmp(des->local_symbol(path), 1);
des->add_signal(tmp);
connect(tmp->pin(0), sig->pin(idx));
sig = tmp;
}
return sig;
}
/*
* Elaborate a number as a NetConst object.
*/
NetNet* PENumber::elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
unsigned width = value_->len();
if ((lwidth > 0) && (lwidth < width))
width = lwidth;
NetNet*net = new NetNet(0, des->local_symbol(path),
NetNet::IMPLICIT, width);
net->local_flag(true);
for (unsigned idx = 0 ; idx < width ; idx += 1) {
NetConst*tmp = new NetConst(des->local_symbol(path),
value_->get(idx));
des->add_node(tmp);
connect(net->pin(idx), tmp->pin(0));
}
des->add_signal(net);
return net;
}
/*
* Elaborate the ternary operator in a netlist by creating a LPM_MUX
* with width matching the result, size == 2 and 1 select input.
@@ -354,7 +877,7 @@ NetNet* PETernary::elaborate_net(Design*des, const string&path,
assert(width == tru_sig->pin_count());
assert(expr_sig->pin_count() == 1);
NetNet*sig = new NetNet(des->local_symbol(path), NetNet::WIRE,
NetNet*sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
tru_sig->pin_count());
sig->local_flag(true);
@@ -366,10 +889,43 @@ NetNet* PETernary::elaborate_net(Design*des, const string&path,
connect(mux->pin_Data(idx,0), fal_sig->pin(idx));
connect(mux->pin_Data(idx,1), tru_sig->pin(idx));
}
des->add_signal(sig);
des->add_node(mux);
return sig;
}
/*
* $Log: elab_net.cc,v $
* Revision 1.11 1999/12/02 04:08:10 steve
* Elaborate net repeat concatenations.
*
* Revision 1.10 1999/11/30 04:33:41 steve
* Put implicitly defined signals in the scope.
*
* Revision 1.9 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.8 1999/11/21 17:35:37 steve
* Memory name lookup handles scopes.
*
* Revision 1.7 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.6 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.5 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.4 1999/11/05 23:36:31 steve
* Forgot to return the mux for use after elaboration.
*
* Revision 1.3 1999/11/05 21:45:19 steve
* Fix NetConst being set to zero width, and clean
* up elaborate_set_cmp_ for NetEBinary.
*
* Revision 1.2 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
+84 -588
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: elaborate.cc,v 1.121 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: elaborate.cc,v 1.132 1999/12/02 04:08:10 steve Exp $"
#endif
/*
@@ -54,8 +54,9 @@ static const map<string,PUdp*>* udplist = 0;
* elaboration this creates an object in the design that represent the
* defined item.
*/
void PWire::elaborate(Design*des, const string&path) const
void PWire::elaborate(Design*des, NetScope*scope) const
{
const string path = scope->name();
NetNet::Type wtype = type_;
if (wtype == NetNet::IMPLICIT)
wtype = NetNet::WIRE;
@@ -141,7 +142,7 @@ void PWire::elaborate(Design*des, const string&path) const
} else {
NetNet*sig = new NetNet(path + "." + name_, wtype, msb, lsb);
NetNet*sig = new NetNet(scope, path + "." + name_, wtype, msb, lsb);
sig->set_line(*this);
sig->port_type(port_type_);
sig->set_attributes(attributes);
@@ -290,7 +291,7 @@ void PGBuiltin::elaborate(Design*des, const string&path) const
else
index = low - idx;
tmp << name << "<" << index << ">";
tmp << name << "<" << index << ">" << ends;
const string inm = tmp.str();
switch (type()) {
@@ -376,7 +377,8 @@ void PGBuiltin::elaborate(Design*des, const string&path) const
void PGModule::elaborate_mod_(Design*des, Module*rmod, const string&path) const
{
assert(get_name() != "");
const string my_name = path + "." + get_name();
NetScope*my_scope = des->make_scope(path, NetScope::MODULE, get_name());
const string my_name = my_scope -> name();
const svector<PExpr*>*pins;
@@ -445,7 +447,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, const string&path) const
// elaboration causes the module to generate a netlist with
// the ports represented by NetNet objects. I will find them
// later.
rmod->elaborate(des, my_name, overrides_);
rmod->elaborate(des, my_scope, overrides_);
// Now connect the ports of the newly elaborated designs to
// the expressions that are the instantiation parameters. Scan
@@ -591,66 +593,6 @@ void PGModule::elaborate(Design*des, const string&path) const
cerr << get_line() << ": error: Unknown module: " << type_ << endl;
}
/*
* The concatenation operator, as a net, is a wide signal that is
* connected to all the pins of the elaborated expression nets.
*/
NetNet* PEConcat::elaborate_net(Design*des, const string&path,
unsigned,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
svector<NetNet*>nets (parms_.count());
unsigned pins = 0;
unsigned errors = 0;
if (repeat_) {
cerr << get_line() << ": sorry: I do not know how to"
" elaborate repeat concatenation nets." << endl;
return 0;
}
/* Elaborate the operands of the concatenation. */
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
nets[idx] = parms_[idx]->elaborate_net(des, path, 0,
rise,fall,decay);
if (nets[idx] == 0)
errors += 1;
else
pins += nets[idx]->pin_count();
}
/* If any of the sub expressions failed to elaborate, then
delete all those that did and abort myself. */
if (errors) {
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
if (nets[idx]) delete nets[idx];
}
des->errors += 1;
return 0;
}
/* Make the temporary signal that connects to all the
operands, and connect it up. Scan the operands of the
concat operator from least significant to most significant,
which is opposite from how they are given in the list. */
NetNet*osig = new NetNet(des->local_symbol(path),
NetNet::IMPLICIT, pins);
pins = 0;
for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) {
NetNet*cur = nets[idx-1];
for (unsigned pin = 0 ; pin < cur->pin_count() ; pin += 1) {
connect(osig->pin(pins), cur->pin(pin));
pins += 1;
}
}
osig->local_flag(true);
des->add_signal(osig);
return osig;
}
/*
* The concatenation is also OK an an l-value. This method elaborates
* it as a structural l-value.
@@ -690,7 +632,7 @@ NetNet* PEConcat::elaborate_lnet(Design*des, const string&path) const
operands, and connect it up. Scan the operands of the
concat operator from least significant to most significant,
which is opposite from how they are given in the list. */
NetNet*osig = new NetNet(des->local_symbol(path),
NetNet*osig = new NetNet(0, des->local_symbol(path),
NetNet::IMPLICIT, pins);
pins = 0;
for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) {
@@ -706,236 +648,6 @@ NetNet* PEConcat::elaborate_lnet(Design*des, const string&path) const
return osig;
}
NetNet* PEIdent::elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
NetNet*sig = des->find_signal(path, text_);
if (sig == 0) {
if (des->find_memory(path+"."+text_)) {
cerr << get_line() << ": sorry: memories not supported"
" in this context." << endl;
return 0;
}
if (const NetExpr*pe = des->find_parameter(path, text_)) {
const NetEConst*pc = dynamic_cast<const NetEConst*>(pe);
assert(pc);
verinum pvalue = pc->value();
sig = new NetNet(path+"."+text_, NetNet::IMPLICIT,
pc->expr_width());
for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) {
NetConst*cp = new NetConst(des->local_symbol(path),
pvalue[idx]);
connect(sig->pin(idx), cp->pin(0));
des->add_node(cp);
}
} else {
sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, 1);
des->add_signal(sig);
cerr << get_line() << ": warning: Implicitly defining "
"wire " << path << "." << text_ << "." << endl;
}
}
assert(sig);
if (msb_ && lsb_) {
verinum*mval = msb_->eval_const(des, path);
if (mval == 0) {
cerr << msb_->get_line() << ": error: unable to "
"evaluate constant expression: " << *msb_ <<
endl;
des->errors += 1;
return 0;
}
verinum*lval = lsb_->eval_const(des, path);
if (lval == 0) {
cerr << lsb_->get_line() << ": error: unable to "
"evaluate constant expression: " << *lsb_ <<
endl;
delete mval;
des->errors += 1;
return 0;
}
assert(mval);
assert(lval);
unsigned midx = sig->sb_to_idx(mval->as_long());
unsigned lidx = sig->sb_to_idx(lval->as_long());
if (midx >= lidx) {
NetTmp*tmp = new NetTmp(midx-lidx+1);
if (tmp->pin_count() > sig->pin_count()) {
cerr << get_line() << ": bit select out of "
<< "range for " << sig->name() << endl;
return sig;
}
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
connect(tmp->pin(idx-lidx), sig->pin(idx));
sig = tmp;
} else {
NetTmp*tmp = new NetTmp(lidx-midx+1);
assert(tmp->pin_count() <= sig->pin_count());
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
connect(tmp->pin(idx-midx), sig->pin(idx));
sig = tmp;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, path);
if (mval == 0) {
cerr << get_line() << ": index of " << text_ <<
" needs to be constant in this context." <<
endl;
des->errors += 1;
return 0;
}
assert(mval);
unsigned idx = sig->sb_to_idx(mval->as_long());
if (idx >= sig->pin_count()) {
cerr << get_line() << "; index " << sig->name() <<
"[" << mval->as_long() << "] out of range." << endl;
des->errors += 1;
idx = 0;
}
NetTmp*tmp = new NetTmp(1);
connect(tmp->pin(0), sig->pin(idx));
sig = tmp;
}
return sig;
}
/*
* Identifiers in continuous assignment l-values are limited to wires
* and that ilk. Detect registers and memories here and report errors.
*/
NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const
{
NetNet*sig = des->find_signal(path, text_);
if (sig == 0) {
/* Don't allow memories here. Is it a memory? */
if (des->find_memory(path+"."+text_)) {
cerr << get_line() << ": error: memories (" << text_
<< ") cannot be l-values in continuous "
<< "assignments." << endl;
return 0;
}
/* Fine, create an implicit wire as an l-value. */
sig = new NetNet(path+"."+text_, NetNet::IMPLICIT, 1);
des->add_signal(sig);
cerr << get_line() << ": warning: Implicitly defining "
"wire " << path << "." << text_ << "." << endl;
}
assert(sig);
/* Don't allow registers as assign l-values. */
if (sig->type() == NetNet::REG) {
cerr << get_line() << ": error: registers (" << sig->name()
<< ") cannot be l-values in continuous"
<< " assignments." << endl;
return 0;
}
if (msb_ && lsb_) {
/* Detect a part select. Evaluate the bits and elaborate
the l-value by creating a sub-net that links to just
the right pins. */
verinum*mval = msb_->eval_const(des, path);
assert(mval);
verinum*lval = lsb_->eval_const(des, path);
assert(lval);
unsigned midx = sig->sb_to_idx(mval->as_long());
unsigned lidx = sig->sb_to_idx(lval->as_long());
if (midx >= lidx) {
NetTmp*tmp = new NetTmp(midx-lidx+1);
if (tmp->pin_count() > sig->pin_count()) {
cerr << get_line() << ": bit select out of "
<< "range for " << sig->name() << endl;
return sig;
}
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
connect(tmp->pin(idx-lidx), sig->pin(idx));
sig = tmp;
} else {
NetTmp*tmp = new NetTmp(lidx-midx+1);
assert(tmp->pin_count() <= sig->pin_count());
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
connect(tmp->pin(idx-midx), sig->pin(idx));
sig = tmp;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, path);
if (mval == 0) {
cerr << get_line() << ": index of " << text_ <<
" needs to be constant in this context." <<
endl;
des->errors += 1;
return 0;
}
assert(mval);
unsigned idx = sig->sb_to_idx(mval->as_long());
if (idx >= sig->pin_count()) {
cerr << get_line() << "; index " << sig->name() <<
"[" << mval->as_long() << "] out of range." << endl;
des->errors += 1;
idx = 0;
}
NetTmp*tmp = new NetTmp(1);
connect(tmp->pin(0), sig->pin(idx));
sig = tmp;
}
return sig;
}
/*
* Elaborate a number as a NetConst object.
*/
NetNet* PENumber::elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const
{
unsigned width = value_->len();
if (lwidth < width)
width = lwidth;
NetNet*net = new NetNet(des->local_symbol(path),
NetNet::IMPLICIT, width);
net->local_flag(true);
for (unsigned idx = 0 ; idx < width ; idx += 1) {
NetConst*tmp = new NetConst(des->local_symbol(path),
value_->get(idx));
des->add_node(tmp);
connect(net->pin(idx), tmp->pin(0));
}
des->add_signal(net);
return net;
}
NetNet* PEUnary::elaborate_net(Design*des, const string&path,
unsigned width,
unsigned long rise,
@@ -954,7 +666,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
NetLogic*gate;
switch (op_) {
case '~': // Bitwise NOT
sig = new NetNet(des->local_symbol(path), NetNet::WIRE,
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE,
sub_sig->pin_count());
sig->local_flag(true);
for (unsigned idx = 0 ; idx < sub_sig->pin_count() ; idx += 1) {
@@ -972,7 +684,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
case 'N': // Reduction NOR
case '!': // Reduction NOT
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
sig->local_flag(true);
gate = new NetLogic(des->local_symbol(path),
1+sub_sig->pin_count(),
@@ -989,7 +701,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
break;
case '&': // Reduction AND
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
sig->local_flag(true);
gate = new NetLogic(des->local_symbol(path),
1+sub_sig->pin_count(),
@@ -1006,7 +718,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
break;
case '|': // Reduction OR
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
sig->local_flag(true);
gate = new NetLogic(des->local_symbol(path),
1+sub_sig->pin_count(),
@@ -1023,7 +735,7 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
break;
case '^': // Reduction XOR
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
sig = new NetNet(0, des->local_symbol(path), NetNet::WIRE);
sig->local_flag(true);
gate = new NetLogic(des->local_symbol(path),
1+sub_sig->pin_count(),
@@ -1277,7 +989,7 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const
const PEIdent*id = dynamic_cast<const PEIdent*>(lval());
if (id == 0) break;
if (NetMemory*mem = des->find_memory(path+"."+id->name()))
if (NetMemory*mem = des->find_memory(path, id->name()))
return assign_to_memory_(mem, id->msb_, des, path);
} while(0);
@@ -1297,9 +1009,21 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const
/* Elaborate the r-value expression. */
assert(rval());
NetExpr*rv = rval()->elaborate_expr(des, path);
if (rv == 0)
NetExpr*rv;
if (verinum*val = rval()->eval_const(des,path)) {
rv = new NetEConst(*val);
delete val;
} else if (rv = rval()->elaborate_expr(des, path)) {
/* OK, go on. */
} else {
/* Unable to elaborate expression. Retreat. */
return 0;
}
assert(rv);
@@ -1342,7 +1066,7 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const
return 0;
}
NetNet*tmp = new NetNet(n, NetNet::REG, wid);
NetNet*tmp = new NetNet(0, n, NetNet::REG, wid);
tmp->set_line(*this);
des->add_signal(tmp);
@@ -1358,7 +1082,6 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const
/* Generate an assignment of the temporary to the r-value... */
n = des->local_symbol(path);
NetESignal*sig = new NetESignal(tmp);
des->add_node(sig);
NetAssign*a2 = new NetAssign(n, des, wid, sig);
a2->set_line(*this);
des->add_node(a2);
@@ -1473,7 +1196,7 @@ NetProc* PAssignNB::elaborate(Design*des, const string&path) const
const PEIdent*id = dynamic_cast<const PEIdent*>(lval());
if (id == 0) break;
if (NetMemory*mem = des->find_memory(path+"."+id->name()))
if (NetMemory*mem = des->find_memory(path, id->name()))
return assign_to_memory_(mem, id->msb_, des, path);
} while(0);
@@ -1540,7 +1263,9 @@ NetProc* PBlock::elaborate(Design*des, const string&path) const
NetBlock*cur = new NetBlock(type);
bool fail_flag = false;
string npath = name_.length()? (path+"."+name_) : path;
string npath = name_.length()
? des->make_scope(path, NetScope::BEGIN_END, name_) -> name()
: path;
// Handle the special case that the block contains only one
// statement. There is no need to keep the block node.
@@ -1699,6 +1424,11 @@ NetProc* PCallTask::elaborate(Design*des, const string&path) const
/*
* A call to a system task involves elaborating all the parameters,
* then passing the list to the NetSTask object.
*XXXX
* There is a single special in the call to a system task. Normally,
* an expression cannot take an unindexed memory. However, it is
* possible to take a system task parameter a memory if the expression
* is trivial.
*/
NetProc* PCallTask::elaborate_sys(Design*des, const string&path) const
{
@@ -1706,6 +1436,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, const string&path) const
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
PExpr*ex = parm(idx);
eparms[idx] = ex? ex->elaborate_expr(des, path) : 0;
}
@@ -1836,7 +1567,6 @@ NetProc* PCallTask::elaborate_usr(Design*des, const string&path) const
for (unsigned pi = 0 ; pi < val->pin_count() ; pi += 1)
connect(val->pin(pi), ass->pin(pi));
des->add_node(sig);
des->add_node(ass);
block->append(ass);
}
@@ -2161,8 +1891,9 @@ NetProc* PWhile::elaborate(Design*des, const string&path) const
return loop;
}
bool Module::elaborate(Design*des, const string&path, svector<PExpr*>*overrides_) const
bool Module::elaborate(Design*des, NetScope*scope, svector<PExpr*>*overrides_) const
{
const string path = scope->name();
bool result_flag = true;
// Generate all the parameters that this instance of this
@@ -2247,7 +1978,7 @@ bool Module::elaborate(Design*des, const string&path, svector<PExpr*>*overrides_
; wt != wl.end()
; wt ++ ) {
(*wt)->elaborate(des, path);
(*wt)->elaborate(des, scope);
}
// Elaborate functions.
@@ -2341,9 +2072,11 @@ Design* elaborate(const map<string,Module*>&modules,
// module and elaborate what I find.
Design*des = new Design;
NetScope*scope = des->make_root_scope(root);
modlist = &modules;
udplist = &primitives;
bool rc = rmod->elaborate(des, root, (svector<PExpr*>*)0);
bool rc = rmod->elaborate(des, scope, (svector<PExpr*>*)0);
modlist = 0;
udplist = 0;
@@ -2357,6 +2090,44 @@ Design* elaborate(const map<string,Module*>&modules,
/*
* $Log: elaborate.cc,v $
* Revision 1.132 1999/12/02 04:08:10 steve
* Elaborate net repeat concatenations.
*
* Revision 1.131 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.130 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.129 1999/11/24 04:01:58 steve
* Detect and list scope names.
*
* Revision 1.128 1999/11/21 20:03:24 steve
* Handle multiply in constant expressions.
*
* Revision 1.127 1999/11/21 17:35:37 steve
* Memory name lookup handles scopes.
*
* Revision 1.126 1999/11/21 01:16:51 steve
* Fix coding errors handling names of logic devices,
* and add support for buf device in vvm.
*
* Revision 1.125 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.124 1999/11/18 03:52:19 steve
* Turn NetTmp objects into normal local NetNet objects,
* and add the nodangle functor to clean up the local
* symbols generated by elaboration and other steps.
*
* Revision 1.123 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.122 1999/11/05 21:45:19 steve
* Fix NetConst being set to zero width, and clean
* up elaborate_set_cmp_ for NetEBinary.
*
* Revision 1.121 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
@@ -2434,280 +2205,5 @@ Design* elaborate(const map<string,Module*>&modules,
* Allow expanding of additive operators.
*
* Revision 1.100 1999/09/25 02:57:30 steve
* Parse system function calls.
*
* Revision 1.99 1999/09/23 03:56:57 steve
* Support shift operators.
*
* Revision 1.98 1999/09/23 02:28:27 steve
* internal error message for funky comparison width.
*
* Revision 1.97 1999/09/23 00:21:54 steve
* Move set_width methods into a single file,
* Add the NetEBLogic class for logic expressions,
* Fix error setting with of && in if statements.
*
* Revision 1.96 1999/09/22 21:25:42 steve
* Expand bits in delayed assignments.
*
* Revision 1.95 1999/09/22 04:30:04 steve
* Parse and elaborate named for/join blocks.
*
* Revision 1.94 1999/09/22 02:00:48 steve
* assignment with blocking event delay.
*
* Revision 1.93 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.92 1999/09/18 22:23:50 steve
* Match bit widths comming out of task output ports.
*
* Revision 1.91 1999/09/18 02:51:35 steve
* report non-constant part select expressions.
*
* Revision 1.90 1999/09/18 01:53:08 steve
* Detect constant lessthen-equal expressions.
*
* Revision 1.89 1999/09/17 02:06:25 steve
* Handle unconnected module ports.
*
* Revision 1.88 1999/09/16 04:18:15 steve
* elaborate concatenation repeats.
*
* Revision 1.87 1999/09/16 00:33:45 steve
* Handle implicit !=0 in if statements.
*
* Revision 1.86 1999/09/15 04:17:52 steve
* separate assign lval elaboration for error checking.
*
* Revision 1.85 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.84 1999/09/14 01:50:52 steve
* implicitly declare wires if needed.
*
* Revision 1.83 1999/09/13 03:10:59 steve
* Clarify msb/lsb in context of netlist. Properly
* handle part selects in lval and rval of expressions,
* and document where the least significant bit goes
* in NetNet objects.
*
* Revision 1.82 1999/09/12 01:16:51 steve
* Pad r-values in certain assignments.
*
* Revision 1.81 1999/09/10 04:04:06 steve
* Add ternary elaboration.
*
* Revision 1.80 1999/09/08 04:05:30 steve
* Allow assign to not match rvalue width.
*
* Revision 1.79 1999/09/08 02:24:39 steve
* Empty conditionals ([email protected])
*
* Revision 1.78 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.77 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.76 1999/09/02 01:59:27 steve
* Parse non-blocking assignment delays.
*
* Revision 1.75 1999/09/01 20:46:19 steve
* Handle recursive functions and arbitrary function
* references to other functions, properly pass
* function parameters and save function results.
*
* Revision 1.74 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.73 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.72 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.71 1999/08/18 04:00:02 steve
* Fixup spelling and some error messages. <[email protected]>
*
* Revision 1.70 1999/08/08 20:06:06 steve
* Uninitialized low and high indices for single gate syntax
*
* Revision 1.69 1999/08/06 04:05:28 steve
* Handle scope of parameters.
*
* Revision 1.68 1999/08/05 04:58:57 steve
* Allow integers as register lvalues.
*
* Revision 1.67 1999/08/04 02:13:02 steve
* Elaborate module ports that are concatenations of
* module signals.
*
* Revision 1.66 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
*
* Revision 1.65 1999/08/01 21:48:11 steve
* set width of procedural r-values when then
* l-value is a memory word.
*
* Revision 1.64 1999/08/01 21:18:55 steve
* elaborate rise/fall/decay for continuous assign.
*
* Revision 1.63 1999/08/01 16:34:50 steve
* Parse and elaborate rise/fall/decay times
* for gates, and handle the rules for partial
* lists of times.
*
* Revision 1.62 1999/07/31 03:16:54 steve
* move binary operators to derived classes.
*
* Revision 1.61 1999/07/28 03:46:57 steve
* Handle no ports at all for tasks.
*
* Revision 1.60 1999/07/24 19:19:06 steve
* Add support for task output and inout ports.
*
* Revision 1.59 1999/07/24 02:11:20 steve
* Elaborate task input ports.
*
* Revision 1.58 1999/07/18 21:17:50 steve
* Add support for CE input to XNF DFF, and do
* complete cleanup of replaced design nodes.
*
* Revision 1.57 1999/07/17 19:50:59 steve
* netlist support for ternary operator.
*
* Revision 1.56 1999/07/17 18:06:02 steve
* Better handling of bit width of + operators.
*
* Revision 1.55 1999/07/17 03:08:31 steve
* part select in expressions.
*
* Revision 1.54 1999/07/13 04:08:26 steve
* Construct delayed assignment as an equivalent block.
*
* Revision 1.53 1999/07/12 00:59:36 steve
* procedural blocking assignment delays.
*
* Revision 1.52 1999/07/10 03:00:05 steve
* Proper initialization of registers.
*
* Revision 1.51 1999/07/10 02:19:26 steve
* Support concatenate in l-values.
*
* Revision 1.50 1999/07/03 02:12:51 steve
* Elaborate user defined tasks.
*
* Revision 1.49 1999/06/24 04:45:29 steve
* Elaborate wide structoral bitwise OR.
*
* Revision 1.48 1999/06/24 04:24:18 steve
* Handle expression widths for EEE and NEE operators,
* add named blocks and scope handling,
* add registers declared in named blocks.
*
* Revision 1.47 1999/06/19 21:06:16 steve
* Elaborate and supprort to vvm the forever
* and repeat statements.
*
* Revision 1.46 1999/06/17 05:34:42 steve
* Clean up interface of the PWire class,
* Properly match wire ranges.
*
* Revision 1.45 1999/06/15 05:38:39 steve
* Support case expression lists.
*
* Revision 1.44 1999/06/15 03:44:53 steve
* Get rid of the STL vector template.
*
* Revision 1.43 1999/06/13 23:51:16 steve
* l-value part select for procedural assignments.
*
* Revision 1.42 1999/06/13 16:30:06 steve
* Unify the NetAssign constructors a bit.
*
* Revision 1.41 1999/06/13 04:46:54 steve
* Add part select lvalues to AssignNB.
*
* Revision 1.40 1999/06/12 23:16:37 steve
* Handle part selects as l-values to continuous assign.
*
* Revision 1.39 1999/06/10 04:03:53 steve
* Add support for the Ternary operator,
* Add support for repeat concatenation,
* Correct some seg faults cause by elaboration
* errors,
* Parse the casex anc casez statements.
*
* Revision 1.38 1999/06/09 03:00:06 steve
* Add support for procedural concatenation expression.
*
* Revision 1.37 1999/06/09 00:58:06 steve
* Support for binary | (Stephen Tell)
*
* Revision 1.36 1999/06/07 02:23:31 steve
* Support non-blocking assignment down to vvm.
*
* Revision 1.35 1999/06/06 23:07:43 steve
* Drop degenerate blocks.
*
* Revision 1.34 1999/06/06 20:45:38 steve
* Add parse and elaboration of non-blocking assignments,
* Replace list<PCase::Item*> with an svector version,
* Add integer support.
*
* Revision 1.33 1999/06/03 05:16:25 steve
* Compile time evalutation of constant expressions.
*
* Revision 1.32 1999/06/02 15:38:46 steve
* Line information with nets.
*
* Revision 1.31 1999/05/31 15:45:35 steve
* Fix error message.
*
* Revision 1.30 1999/05/30 01:11:46 steve
* Exressions are trees that can duplicate, and not DAGS.
*
* Revision 1.29 1999/05/29 02:36:17 steve
* module parameter bind by name.
*
* Revision 1.28 1999/05/27 04:13:08 steve
* Handle expression bit widths with non-fatal errors.
*
* Revision 1.27 1999/05/20 04:31:45 steve
* Much expression parsing work,
* mark continuous assigns with source line info,
* replace some assertion failures with Sorry messages.
*
* Revision 1.26 1999/05/16 05:08:42 steve
* Redo constant expression detection to happen
* after parsing.
*
* Parse more operators and expressions.
*
* Revision 1.25 1999/05/10 00:16:58 steve
* Parse and elaborate the concatenate operator
* in structural contexts, Replace vector<PExpr*>
* and list<PExpr*> with svector<PExpr*>, evaluate
* constant expressions with parameters, handle
* memories as lvalues.
*
* Parse task declarations, integer types.
*
* Revision 1.24 1999/05/05 03:04:46 steve
* Fix handling of null delay statements.
*
* Revision 1.23 1999/05/01 20:43:55 steve
* Handle wide events, such as @(a) where a has
* many bits in it.
*
* Add to vvm the binary ^ and unary & operators.
*
* Dump events a bit more completely.
*
* Revision 1.22 1999/05/01 02:57:53 steve
* Handle much more complex event expressions.
*/
+44 -6
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: emit.cc,v 1.26 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $"
#endif
/*
@@ -65,6 +65,16 @@ void NetCaseCmp::emit_node(ostream&o, struct target_t*tgt) const
tgt->net_case_cmp(o, this);
}
void NetCLShift::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_clshift(o, this);
}
void NetCompare::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_compare(o, this);
}
void NetConst::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_const(o, this);
@@ -80,6 +90,11 @@ void NetMux::emit_node(ostream&o, struct target_t*tgt) const
tgt->lpm_mux(o, this);
}
void NetRamDq::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_ram_dq(o, this);
}
void NetNEvent::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_event(o, this);
@@ -240,6 +255,13 @@ bool Design::emit(ostream&o, struct target_t*tgt) const
bool rc = true;
tgt->start_design(o, this);
// enumerate the scopes
{ map<string,NetScope*>::const_iterator sc;
for (sc = scopes_.begin() ; sc != scopes_.end() ; sc++) {
tgt->scope(o, (*sc).second);
}
}
// emit signals
if (signals_) {
NetNet*cur = signals_->sig_next_;
@@ -324,6 +346,11 @@ void NetEParam::expr_scan(struct expr_scan_t*tgt) const
<< endl;
}
void NetEScope::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_scope(this);
}
void NetEUFunc::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_ufunc(this);
@@ -334,11 +361,6 @@ void NetESignal::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_signal(this);
}
void NetESignal::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_esignal(o, this);
}
void NetESubSignal::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_subsignal(this);
@@ -367,6 +389,22 @@ bool emit(ostream&o, const Design*des, const char*type)
/*
* $Log: emit.cc,v $
* Revision 1.31 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.30 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.29 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.28 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.27 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.26 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
+58 -4
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: eval.cc,v 1.9 1999/10/08 17:48:09 steve Exp $"
#ident "$Id: eval.cc,v 1.12 1999/11/30 04:48:17 steve Exp $"
#endif
# include "PExpr.h"
@@ -42,17 +42,45 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
switch (op_) {
case '+': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv+rv, l->len());
break;
}
case '-': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv-rv, l->len());
break;
}
case '*': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv * rv, l->len());
break;
}
case '/': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv / rv, l->len());
break;
}
case '%': {
assert(l->is_defined());
assert(r->is_defined());
long lv = l->as_long();
long rv = r->as_long();
res = new verinum(lv % rv, l->len());
break;
}
default:
delete l;
delete r;
@@ -68,12 +96,13 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
*/
verinum* PEIdent::eval_const(const Design*des, const string&path) const
{
assert(msb_ == 0);
const NetExpr*expr = des->find_parameter(path, text_);
if (expr == 0)
return 0;
assert(msb_ == 0);
if (dynamic_cast<const NetEParam*>(expr)) {
cerr << get_line() << ": sorry: I cannot evaluate ``" <<
text_ << "'' in this context." << endl;
@@ -90,14 +119,39 @@ verinum* PENumber::eval_const(const Design*, const string&) const
return new verinum(value());
}
verinum* PETernary::eval_const(const Design*, const string&) const
verinum* PETernary::eval_const(const Design*des, const string&path) const
{
assert(0);
verinum*test = expr_->eval_const(des, path);
if (test == 0)
return 0;
verinum::V bit = test->get(0);
delete test;
switch (bit) {
case verinum::V0:
return fal_->eval_const(des, path);
case verinum::V1:
return tru_->eval_const(des, path);
default:
return 0;
// XXXX It is possible to handle this case if both fal_
// and tru_ are constant. Someday...
}
}
/*
* $Log: eval.cc,v $
* Revision 1.12 1999/11/30 04:48:17 steve
* Handle evaluation of ternary during elaboration.
*
* Revision 1.11 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.10 1999/11/21 20:03:24 steve
* Handle multiply in constant expressions.
*
* Revision 1.9 1999/10/08 17:48:09 steve
* Support + in constant expressions.
*
+78 -9
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: expr_synth.cc,v 1.2 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: expr_synth.cc,v 1.6 1999/11/28 23:42:02 steve Exp $"
#endif
# include "netlist.h"
@@ -31,6 +31,44 @@ NetNet* NetExpr::synthesize(Design*des)
return 0;
}
/*
* Make an LPM_ADD_SUB device from addition operators.
*/
NetNet* NetEBAdd::synthesize(Design*des)
{
assert((op()=='+') || (op()=='-'));
string path = des->local_symbol("SYNTH");
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
assert(lsig->pin_count() == rsig->pin_count());
unsigned width=lsig->pin_count();
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
string oname = des->local_symbol(path);
NetAddSub *adder = new NetAddSub(oname, width);
for (unsigned idx = 0 ; idx < width; idx += 1) {
connect(lsig->pin(idx), adder->pin_DataA(idx));
connect(rsig->pin(idx), adder->pin_DataB(idx));
connect(osig->pin(idx), adder->pin_Result(idx));
}
des->add_node(adder);
des->add_signal(osig);
switch (op()) {
case '+':
adder->attribute("LPM_Direction", "ADD");
break;
case '-':
adder->attribute("LPM_Direction", "SUB");
break;
}
return osig;
}
/*
* The bitwise logic operators are turned into discrete gates pretty
* easily. Synthesize the left and right sub-expressions to get
@@ -44,7 +82,7 @@ NetNet* NetEBBits::synthesize(Design*des)
NetNet*rsig = right_->synthesize(des);
assert(lsig->pin_count() == rsig->pin_count());
NetNet*osig = new NetNet(path, NetNet::IMPLICIT, lsig->pin_count());
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, lsig->pin_count());
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
string oname = des->local_symbol(path);
@@ -81,6 +119,22 @@ NetNet* NetEBBits::synthesize(Design*des)
return osig;
}
NetNet* NetEConst::synthesize(Design*des)
{
string path = des->local_symbol("SYNTH");
unsigned width=expr_width();
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
for (unsigned idx = 0 ; idx < width; idx += 1) {
string oname = des->local_symbol(path);
NetConst *c = new NetConst(oname, value().get(idx));
connect(osig->pin(idx), c->pin(0));
des->add_node(c);
}
des->add_signal(osig);
return osig;
}
/*
* The bitwise unary logic operator (there is only one) is turned
* into discrete gates just as easily as the binary ones above.
@@ -90,7 +144,7 @@ NetNet* NetEUBits::synthesize(Design*des)
string path = des->local_symbol("SYNTH");
NetNet*isig = expr_->synthesize(des);
NetNet*osig = new NetNet(path, NetNet::IMPLICIT, isig->pin_count());
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, isig->pin_count());
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
string oname = des->local_symbol(path);
@@ -124,7 +178,7 @@ NetNet* NetETernary::synthesize(Design *des)
assert(csig->pin_count() == 1);
assert(tsig->pin_count() == fsig->pin_count());
unsigned width=tsig->pin_count();
NetNet*osig = new NetNet(path, NetNet::IMPLICIT, width);
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
string oname = des->local_symbol(path);
NetMux *mux = new NetMux(oname, width, 2, 1);
@@ -141,15 +195,30 @@ NetNet* NetETernary::synthesize(Design *des)
NetNet* NetESignal::synthesize(Design*des)
{
NetNet*sig = new NetNet(name(), NetNet::WIRE, pin_count());
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1)
connect(sig->pin(idx), pin(idx));
des->add_signal(sig);
return sig;
return net_;
}
/*
* $Log: expr_synth.cc,v $
* Revision 1.6 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.5 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.4 1999/11/19 03:00:59 steve
* Whoops, created a signal with a duplicate name.
*
* Revision 1.3 1999/11/05 04:40:40 steve
* Patch to synthesize LPM_ADD_SUB from expressions,
* Thanks to Larry Doolittle. Also handle constants
* in expressions.
*
* Synthesize adders in XNF, based on a patch from
* Larry. Accept synthesis of constants from Larry
* as is.
*
* Revision 1.2 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
+50 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: functor.cc,v 1.3 1999/11/01 02:07:40 steve Exp $"
#ident "$Id: functor.cc,v 1.5 1999/12/01 06:06:16 steve Exp $"
#endif
# include "functor.h"
@@ -45,8 +45,9 @@ void Design::functor(functor_t*fun)
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
NetNet*tmp = cur->sig_next_;
fun->signal(this, cur);
cur = cur->sig_next_;
cur = tmp;
} while (cur != signals_->sig_next_);
}
@@ -79,8 +80,55 @@ void NetFF::functor_node(Design*des, functor_t*fun)
fun->lpm_ff(des, this);
}
proc_match_t::~proc_match_t()
{
}
int NetProc::match_proc(proc_match_t*that)
{
return 0;
}
int proc_match_t::assign(NetAssign*)
{
return 0;
}
int NetAssign::match_proc(proc_match_t*that)
{
return that->assign(this);
}
int proc_match_t::condit(NetCondit*)
{
return 0;
}
int NetCondit::match_proc(proc_match_t*that)
{
return that->condit(this);
}
int proc_match_t::pevent(NetPEvent*)
{
return 0;
}
int NetPEvent::match_proc(proc_match_t*that)
{
return that->pevent(this);
}
/*
* $Log: functor.cc,v $
* Revision 1.5 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
* Revision 1.4 1999/11/18 03:52:19 steve
* Turn NetTmp objects into normal local NetNet objects,
* and add the nodangle functor to clean up the local
* symbols generated by elaboration and other steps.
*
* Revision 1.3 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
+13 -1
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: functor.h,v 1.2 1999/11/01 02:07:40 steve Exp $"
#ident "$Id: functor.h,v 1.3 1999/12/01 06:06:16 steve Exp $"
#endif
/*
@@ -46,8 +46,20 @@ struct functor_t {
virtual void lpm_ff(class Design*des, class NetFF*);
};
struct proc_match_t {
virtual ~proc_match_t();
virtual int assign(class NetAssign*);
virtual int condit(class NetCondit*);
virtual int pevent(class NetPEvent*);
};
/*
* $Log: functor.h,v $
* Revision 1.3 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
* Revision 1.2 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
+5 -4
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.6 1999/10/16 20:48:15 steve Exp $"
#ident "$Id: Makefile.in,v 1.6.2.1 1999/12/03 17:43:49 steve Exp $"
#
#
SHELL = /bin/sh
@@ -33,6 +33,7 @@ VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
libexecdir = $(libdir)/ivl
includedir = $(prefix)/include
CC = @CC@
@@ -60,10 +61,10 @@ lexor.c: lexor.lex
parse.h parse.c: parse.y
bison --verbose -t -d parse.y -o parse.c
install: all installdirs $(bindir)/ivlpp
install: all installdirs $(libexecdir)/ivlpp
$(bindir)/ivlpp: ivlpp
$(INSTALL_PROGRAM) ./ivlpp $(bindir)/ivlpp
$(libexecdir)/ivlpp: ivlpp
$(INSTALL_PROGRAM) ./ivlpp $(libexecdir)/ivlpp
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(bindir)
+7 -1
View File
@@ -17,7 +17,7 @@ const char COPYRIGHT[] =
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: main.c,v 1.3 1999/09/05 22:33:18 steve Exp $"
#ident "$Id: main.c,v 1.4 1999/11/29 17:02:21 steve Exp $"
#endif
const char NOTICE[] =
@@ -42,6 +42,9 @@ const char VERSION[] = "$Name: $ $State: Exp $";
# include <malloc.h>
# include <unistd.h>
# include <string.h>
#if defined(HAVE_GETOPT_H)
# include <getopt.h>
#endif
# include "globals.h"
char**include_dir = 0;
@@ -140,6 +143,9 @@ int main(int argc, char*argv[])
/*
* $Log: main.c,v $
* Revision 1.4 1999/11/29 17:02:21 steve
* include getopt if present.
*
* Revision 1.3 1999/09/05 22:33:18 steve
* Take multiple source files on the command line.
*
+29 -2
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.36 1999/09/30 04:51:14 steve Exp $"
#ident "$Id: lexor.lex,v 1.38 1999/11/23 02:49:04 steve Exp $"
#endif
//# define YYSTYPE lexval
@@ -40,6 +40,7 @@ extern YYLTYPE yylloc;
static void reset_lexor();
static void line_directive();
static void line_directive2();
extern int check_identifier(const char*str, int len);
static verinum*make_sized_binary(const char*txt);
@@ -66,6 +67,7 @@ W [ \t\b\f\r]+
%%
^"#line"[ ]+\"[^\"]*\"[ ]+[0-9]+.* { line_directive(); }
^"`line"[ ]+[0-9]+[ ]+\"[^\"]*\".* { line_directive2(); }
[ \t\b\f\r] { ; }
\n { yylloc.first_line += 1; }
@@ -157,7 +159,7 @@ W [ \t\b\f\r]+
yylval.text = strdup(cp);
return PORTNAME; }
[0-9][0-9_]*[ \t]*\'d[ \t]*[0-9][0-9_]* {
[0-9][0-9_]*[ \t]*\'[dD][ \t]*[0-9][0-9_]* {
yylval.number = make_sized_dec(yytext);
return NUMBER; }
[0-9][0-9_]*[ \t]*\'[bB][ \t]*[0-1xzXZ_\?]+ {
@@ -778,6 +780,31 @@ static void line_directive()
yylloc.first_line = strtoul(qt2,0,0);
}
static void line_directive2()
{
assert(strncmp(yytext,"`line",5) == 0);
char*cp = yytext + strlen("`line");
cp += strspn(cp, " ");
yylloc.first_line = strtoul(cp,&cp,10);
cp += strspn(cp, " ");
if (*cp == 0) return;
char*qt1 = strchr(yytext, '"');
assert(qt1);
qt1 += 1;
char*qt2 = strchr(qt1, '"');
assert(qt2);
char*buf = new char[qt2-qt1+1];
strncpy(buf, qt1, qt2-qt1);
buf[qt2-qt1] = 0;
delete[]yylloc.text;
yylloc.text = buf;
}
static void reset_lexor()
{
yyrestart(vl_input);
+15 -2
View File
@@ -19,7 +19,7 @@ const char COPYRIGHT[] =
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: main.cc,v 1.24 1999/11/01 02:07:40 steve Exp $"
#ident "$Id: main.cc,v 1.26 1999/11/29 17:02:21 steve Exp $"
#endif
const char NOTICE[] =
@@ -44,6 +44,9 @@ const char NOTICE[] =
# include <queue>
# include <map>
# include <unistd.h>
#if defined(HAVE_GETOPT_H)
# include <getopt.h>
#endif
# include "pform.h"
# include "netlist.h"
# include "target.h"
@@ -81,6 +84,7 @@ extern void propinit(Design*des);
extern void sigfold(Design*des);
extern void synth(Design*des);
extern void nobufz(Design*des);
extern void nodangle(Design*des);
extern void xnfio(Design*des);
extern void xnfsyn(Design*des);
@@ -91,7 +95,8 @@ static struct net_func_map {
} func_table[] = {
{ "cprop", &cprop },
{ "nobufz", &nobufz },
{ "propinit", &propinit },
{ "nodangle",&nodangle },
{ "propinit",&propinit },
{ "sigfold", &sigfold },
{ "synth", &synth },
{ "xnfio", &xnfio },
@@ -279,6 +284,14 @@ int main(int argc, char*argv[])
/*
* $Log: main.cc,v $
* Revision 1.26 1999/11/29 17:02:21 steve
* include getopt if present.
*
* Revision 1.25 1999/11/18 03:52:19 steve
* Turn NetTmp objects into normal local NetNet objects,
* and add the nodangle functor to clean up the local
* symbols generated by elaboration and other steps.
*
* Revision 1.24 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
+639 -105
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: netlist.cc,v 1.82 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: netlist.cc,v 1.97 1999/12/02 16:58:58 steve Exp $"
#endif
# include <cassert>
@@ -77,9 +77,20 @@ ostream& operator<< (ostream&o, NetNet::Type t)
void connect(NetObj::Link&l, NetObj::Link&r)
{
assert(&l != &r);
assert(l.next_->prev_ == &l);
assert(l.prev_->next_ == &l);
assert(r.next_->prev_ == &r);
assert(r.prev_->next_ == &r);
NetObj::Link* cur = &l;
do {
NetObj::Link*tmp = cur->next_;
// If I stumble on r in the nexus, then stop now because
// we are already connected.
if (tmp == &r) break;
// Pull cur out of left list...
cur->prev_->next_ = cur->next_;
cur->next_->prev_ = cur->prev_;
@@ -93,6 +104,11 @@ void connect(NetObj::Link&l, NetObj::Link&r)
// Go to the next item in the left list.
cur = tmp;
} while (cur != &l);
assert(l.next_->prev_ == &l);
assert(l.prev_->next_ == &l);
assert(r.next_->prev_ == &r);
assert(r.prev_->next_ == &r);
}
NetObj::Link::Link()
@@ -135,6 +151,36 @@ bool NetObj::Link::is_linked(const NetObj::Link&that) const
return false;
}
void NetObj::Link::next_link(NetObj*&net, unsigned&pin)
{
assert(next_->prev_ == this);
assert(prev_->next_ == this);
net = next_->node_;
pin = next_->pin_;
}
void NetObj::Link::next_link(const NetObj*&net, unsigned&pin) const
{
assert(next_->prev_ == this);
assert(prev_->next_ == this);
net = next_->node_;
pin = next_->pin_;
}
NetObj::Link* NetObj::Link::next_link()
{
assert(next_->prev_ == this);
assert(prev_->next_ == this);
return next_;
}
const NetObj::Link* NetObj::Link::next_link() const
{
assert(next_->prev_ == this);
assert(prev_->next_ == this);
return next_;
}
const NetObj*NetObj::Link::get_obj() const
{
return node_;
@@ -242,6 +288,16 @@ const NetNet* find_link_signal(const NetObj*net, unsigned pin, unsigned&bidx)
return 0;
}
NetObj::Link* find_next_output(NetObj::Link*lnk)
{
for (NetObj::Link*cur = lnk->next_link()
; cur != lnk ; cur = cur->next_link())
if (cur->get_dir() == NetObj::Link::OUTPUT)
return cur;
return 0;
}
NetObj::NetObj(const string&n, unsigned np)
: name_(n), npins_(np), delay1_(0), delay2_(0), delay3_(0), mark_(false)
{
@@ -312,32 +368,48 @@ NetNode::~NetNode()
design_->del_node(this);
}
NetNet::NetNet(const string&n, Type t, unsigned npins)
: NetObj(n, npins), sig_next_(0), sig_prev_(0), design_(0),
NetNet::NetNet(NetScope*s, const string&n, Type t, unsigned npins)
: NetObj(n, npins), sig_next_(0), sig_prev_(0), design_(0), scope_(s),
type_(t), port_type_(NOT_A_PORT), msb_(npins-1), lsb_(0),
local_flag_(false)
local_flag_(false), eref_count_(0)
{
ivalue_ = new verinum::V[npins];
for (unsigned idx = 0 ; idx < npins ; idx += 1)
for (unsigned idx = 0 ; idx < npins ; idx += 1) {
pin(idx).set_name("P", idx);
ivalue_[idx] = verinum::Vz;
}
}
NetNet::NetNet(const string&n, Type t, long ms, long ls)
NetNet::NetNet(NetScope*s, const string&n, Type t, long ms, long ls)
: NetObj(n, ((ms>ls)?ms-ls:ls-ms) + 1), sig_next_(0),
sig_prev_(0), design_(0), type_(t), port_type_(NOT_A_PORT),
msb_(ms), lsb_(ls), local_flag_(false)
sig_prev_(0), design_(0), scope_(s), type_(t),
port_type_(NOT_A_PORT), msb_(ms), lsb_(ls), local_flag_(false),
eref_count_(0)
{
ivalue_ = new verinum::V[pin_count()];
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1)
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
pin(idx).set_name("P", idx);
ivalue_[idx] = verinum::Vz;
}
}
NetNet::~NetNet()
{
assert(eref_count_ == 0);
if (design_)
design_->del_signal(this);
}
NetScope* NetNet::scope()
{
return scope_;
}
const NetScope* NetNet::scope() const
{
return scope_;
}
unsigned NetNet::sb_to_idx(long sb) const
{
if (msb_ >= lsb_)
@@ -346,6 +418,28 @@ unsigned NetNet::sb_to_idx(long sb) const
return lsb_ - sb;
}
void NetNet::incr_eref()
{
eref_count_ += 1;
}
void NetNet::decr_eref()
{
assert(eref_count_ > 0);
eref_count_ -= 1;
}
unsigned NetNet::get_eref() const
{
return eref_count_;
}
NetTmp::NetTmp(const string&name, unsigned npins)
: NetNet(0, name, IMPLICIT, npins)
{
local_flag(true);
}
NetProc::NetProc()
: next_(0)
{
@@ -555,6 +649,13 @@ NetObj::Link& NetAddSub::pin_DataA(unsigned idx)
return pin(idx);
}
const NetObj::Link& NetAddSub::pin_DataA(unsigned idx) const
{
idx = 6 + idx*3;
assert(idx < pin_count());
return pin(idx);
}
NetObj::Link& NetAddSub::pin_DataB(unsigned idx)
{
idx = 7 + idx*3;
@@ -562,6 +663,13 @@ NetObj::Link& NetAddSub::pin_DataB(unsigned idx)
return pin(idx);
}
const NetObj::Link& NetAddSub::pin_DataB(unsigned idx) const
{
idx = 7 + idx*3;
assert(idx < pin_count());
return pin(idx);
}
NetObj::Link& NetAddSub::pin_Result(unsigned idx)
{
idx = 8 + idx*3;
@@ -576,6 +684,244 @@ const NetObj::Link& NetAddSub::pin_Result(unsigned idx) const
return pin(idx);
}
/*
* The pinout for the NetCLShift is:
* 0 -- Direction
* 1 -- Underflow
* 2 -- Overflow
* 3 -- Data(0)
* 3+W -- Result(0)
* 3+2W -- Distance(0)
*/
NetCLShift::NetCLShift(const string&n, unsigned width, unsigned width_dist)
: NetNode(n, 3+2*width+width_dist), width_(width), width_dist_(width_dist)
{
pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("Direction", 0);
pin(1).set_dir(NetObj::Link::OUTPUT); pin(1).set_name("Underflow", 0);
pin(2).set_dir(NetObj::Link::OUTPUT); pin(2).set_name("Overflow", 0);
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
pin(3+idx).set_dir(NetObj::Link::INPUT);
pin(3+idx).set_name("Data", idx);
pin(3+width_+idx).set_dir(NetObj::Link::OUTPUT);
pin(3+width_+idx).set_name("Result", idx);
}
for (unsigned idx = 0 ; idx < width_dist_ ; idx += 1) {
pin(3+2*width_+idx).set_dir(NetObj::Link::INPUT);
pin(3+2*width_+idx).set_name("Distance", idx);
}
}
NetCLShift::~NetCLShift()
{
}
unsigned NetCLShift::width() const
{
return width_;
}
unsigned NetCLShift::width_dist() const
{
return width_dist_;
}
NetObj::Link& NetCLShift::pin_Direction()
{
return pin(0);
}
const NetObj::Link& NetCLShift::pin_Direction() const
{
return pin(0);
}
NetObj::Link& NetCLShift::pin_Underflow()
{
return pin(1);
}
const NetObj::Link& NetCLShift::pin_Underflow() const
{
return pin(1);
}
NetObj::Link& NetCLShift::pin_Overflow()
{
return pin(2);
}
const NetObj::Link& NetCLShift::pin_Overflow() const
{
return pin(2);
}
NetObj::Link& NetCLShift::pin_Data(unsigned idx)
{
assert(idx < width_);
return pin(3+idx);
}
const NetObj::Link& NetCLShift::pin_Data(unsigned idx) const
{
assert(idx < width_);
return pin(3+idx);
}
NetObj::Link& NetCLShift::pin_Result(unsigned idx)
{
assert(idx < width_);
return pin(3+width_+idx);
}
const NetObj::Link& NetCLShift::pin_Result(unsigned idx) const
{
assert(idx < width_);
return pin(3+width_+idx);
}
NetObj::Link& NetCLShift::pin_Distance(unsigned idx)
{
assert(idx < width_dist_);
return pin(3+2*width_+idx);
}
const NetObj::Link& NetCLShift::pin_Distance(unsigned idx) const
{
assert(idx < width_dist_);
return pin(3+2*width_+idx);
}
NetCompare::NetCompare(const string&n, unsigned wi)
: NetNode(n, 8+2*wi), width_(wi)
{
pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("Aclr");
pin(1).set_dir(NetObj::Link::INPUT); pin(1).set_name("Clock");
pin(2).set_dir(NetObj::Link::OUTPUT); pin(2).set_name("AGB");
pin(3).set_dir(NetObj::Link::OUTPUT); pin(3).set_name("AGEB");
pin(4).set_dir(NetObj::Link::OUTPUT); pin(4).set_name("AEB");
pin(5).set_dir(NetObj::Link::OUTPUT); pin(5).set_name("ANEB");
pin(6).set_dir(NetObj::Link::OUTPUT); pin(6).set_name("ALB");
pin(7).set_dir(NetObj::Link::OUTPUT); pin(7).set_name("ALEB");
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
pin(8+idx).set_dir(NetObj::Link::INPUT);
pin(8+idx).set_name("DataA", idx);
pin(8+width_+idx).set_dir(NetObj::Link::INPUT);
pin(8+width_+idx).set_name("DataB", idx);
}
}
NetCompare::~NetCompare()
{
}
unsigned NetCompare::width() const
{
return width_;
}
NetObj::Link& NetCompare::pin_Aclr()
{
return pin(0);
}
const NetObj::Link& NetCompare::pin_Aclr() const
{
return pin(0);
}
NetObj::Link& NetCompare::pin_Clock()
{
return pin(1);
}
const NetObj::Link& NetCompare::pin_Clock() const
{
return pin(1);
}
NetObj::Link& NetCompare::pin_AGB()
{
return pin(2);
}
const NetObj::Link& NetCompare::pin_AGB() const
{
return pin(2);
}
NetObj::Link& NetCompare::pin_AGEB()
{
return pin(3);
}
const NetObj::Link& NetCompare::pin_AGEB() const
{
return pin(3);
}
NetObj::Link& NetCompare::pin_AEB()
{
return pin(4);
}
const NetObj::Link& NetCompare::pin_AEB() const
{
return pin(4);
}
NetObj::Link& NetCompare::pin_ANEB()
{
return pin(5);
}
const NetObj::Link& NetCompare::pin_ANEB() const
{
return pin(5);
}
NetObj::Link& NetCompare::pin_ALB()
{
return pin(6);
}
const NetObj::Link& NetCompare::pin_ALB() const
{
return pin(6);
}
NetObj::Link& NetCompare::pin_ALEB()
{
return pin(7);
}
const NetObj::Link& NetCompare::pin_ALEB() const
{
return pin(7);
}
NetObj::Link& NetCompare::pin_DataA(unsigned idx)
{
return pin(8+idx);
}
const NetObj::Link& NetCompare::pin_DataA(unsigned idx) const
{
return pin(8+idx);
}
NetObj::Link& NetCompare::pin_DataB(unsigned idx)
{
return pin(8+width_+idx);
}
const NetObj::Link& NetCompare::pin_DataB(unsigned idx) const
{
return pin(8+width_+idx);
}
/*
* The NetMux class represents an LPM_MUX device. The pinout is assigned
* like so:
@@ -589,7 +935,7 @@ NetMux::NetMux(const string&n, unsigned wi, unsigned si, unsigned sw)
: NetNode(n, 2+wi+sw+wi*si), width_(wi), size_(si), swidth_(sw)
{
pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("Aclr", 0);
pin(1).set_dir(NetObj::Link::INPUT); pin(0).set_name("Clock", 0);
pin(1).set_dir(NetObj::Link::INPUT); pin(1).set_name("Clock", 0);
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
pin_Result(idx).set_dir(NetObj::Link::OUTPUT);
@@ -602,7 +948,7 @@ NetMux::NetMux(const string&n, unsigned wi, unsigned si, unsigned sw)
}
for (unsigned idx = 0 ; idx < swidth_ ; idx += 1) {
pin_Sel(idx).set_dir(Link::OUTPUT);
pin_Sel(idx).set_dir(Link::INPUT);
pin_Sel(idx).set_name("Sel", idx);
}
}
@@ -684,6 +1030,120 @@ const NetObj::Link& NetMux::pin_Data(unsigned w, unsigned s) const
return pin(2+width_+swidth_+s*width_+w);
}
NetRamDq::NetRamDq(const string&n, NetMemory*mem, unsigned awid)
: NetNode(n, 3+2*mem->width()+awid), mem_(mem), awidth_(awid)
{
pin(0).set_dir(NetObj::Link::INPUT); pin(0).set_name("InClock", 0);
pin(1).set_dir(NetObj::Link::INPUT); pin(1).set_name("OutClock", 0);
pin(2).set_dir(NetObj::Link::INPUT); pin(2).set_name("WE", 0);
for (unsigned idx = 0 ; idx < awidth_ ; idx += 1) {
pin(3+idx).set_dir(NetObj::Link::INPUT);
pin(3+idx).set_name("Address", idx);
}
for (unsigned idx = 0 ; idx < width() ; idx += 1) {
pin(3+awidth_+idx).set_dir(NetObj::Link::INPUT);
pin(3+awidth_+idx).set_name("Data", idx);
}
for (unsigned idx = 0 ; idx < width() ; idx += 1) {
pin(3+awidth_+width()+idx).set_dir(NetObj::Link::OUTPUT);
pin(3+awidth_+width()+idx).set_name("Q", idx);
}
}
NetRamDq::~NetRamDq()
{
}
unsigned NetRamDq::width() const
{
return mem_->width();
}
unsigned NetRamDq::awidth() const
{
return awidth_;
}
unsigned NetRamDq::size() const
{
return mem_->count();
}
const NetMemory* NetRamDq::mem() const
{
return mem_;
}
NetObj::Link& NetRamDq::pin_InClock()
{
return pin(0);
}
const NetObj::Link& NetRamDq::pin_InClock() const
{
return pin(0);
}
NetObj::Link& NetRamDq::pin_OutClock()
{
return pin(1);
}
const NetObj::Link& NetRamDq::pin_OutClock() const
{
return pin(1);
}
NetObj::Link& NetRamDq::pin_WE()
{
return pin(2);
}
const NetObj::Link& NetRamDq::pin_WE() const
{
return pin(2);
}
NetObj::Link& NetRamDq::pin_Address(unsigned idx)
{
assert(idx < awidth_);
return pin(3+idx);
}
const NetObj::Link& NetRamDq::pin_Address(unsigned idx) const
{
assert(idx < awidth_);
return pin(3+idx);
}
NetObj::Link& NetRamDq::pin_Data(unsigned idx)
{
assert(idx < width());
return pin(3+awidth_+idx);
}
const NetObj::Link& NetRamDq::pin_Data(unsigned idx) const
{
assert(idx < width());
return pin(3+awidth_+idx);
}
NetObj::Link& NetRamDq::pin_Q(unsigned idx)
{
assert(idx < width());
return pin(3+awidth_+width()+idx);
}
const NetObj::Link& NetRamDq::pin_Q(unsigned idx) const
{
assert(idx < width());
return pin(3+awidth_+width()+idx);
}
/*
* NetAssign
*/
@@ -884,9 +1344,9 @@ void NetCase::set_case(unsigned idx, NetExpr*e, NetProc*p)
NetCaseCmp::NetCaseCmp(const string&n)
: NetNode(n, 3)
{
pin(0).set_dir(Link::OUTPUT);
pin(1).set_dir(Link::INPUT);
pin(2).set_dir(Link::INPUT);
pin(0).set_dir(Link::OUTPUT); pin(0).set_name("O",0);
pin(1).set_dir(Link::INPUT); pin(1).set_name("I",0);
pin(2).set_dir(Link::INPUT); pin(2).set_name("I",1);
}
NetCaseCmp::~NetCaseCmp()
@@ -1288,7 +1748,7 @@ NetEIdent* NetEIdent::dup_expr() const
}
NetEMemory::NetEMemory(NetMemory*m, NetExpr*i)
: mem_(m), idx_(i)
: NetExpr(m->width()), mem_(m), idx_(i)
{
}
@@ -1348,26 +1808,45 @@ NetEParam* NetEParam::dup_expr() const
return 0;
}
NetESignal::NetESignal(NetNet*n)
: NetExpr(n->pin_count()), NetNode(n->name(), n->pin_count())
NetEScope::NetEScope(NetScope*s)
: scope_(s)
{
set_line(*n);
for (unsigned idx = 0 ; idx < n->pin_count() ; idx += 1) {
pin(idx).set_name("P", idx);
connect(pin(idx), n->pin(idx));
}
}
NetESignal::NetESignal(const string&n, unsigned np)
: NetExpr(np), NetNode(n, np)
NetEScope::~NetEScope()
{
expr_width(pin_count());
for(unsigned idx = 0 ; idx < np ; idx += 1)
pin(idx).set_name("P", idx);
}
const NetScope* NetEScope::scope() const
{
return scope_;
}
NetESignal::NetESignal(NetNet*n)
: NetExpr(n->pin_count()), net_(n)
{
net_->incr_eref();
set_line(*n);
}
NetESignal::~NetESignal()
{
net_->decr_eref();
}
const string& NetESignal::name() const
{
return net_->name();
}
unsigned NetESignal::pin_count() const
{
return net_->pin_count();
}
NetObj::Link& NetESignal::pin(unsigned idx)
{
return net_->pin(idx);
}
NetESignal* NetESignal::dup_expr() const
@@ -1498,6 +1977,30 @@ const NetExpr* NetRepeat::expr() const
return expr_;
}
NetScope::NetScope(const string&n)
: type_(NetScope::MODULE), name_(n)
{
}
NetScope::NetScope(const string&p, NetScope::TYPE t)
: type_(t), name_(p)
{
}
NetScope::~NetScope()
{
}
NetScope::TYPE NetScope::type() const
{
return type_;
}
string NetScope::name() const
{
return name_;
}
NetTaskDef::NetTaskDef(const string&n, const svector<NetNet*>&po)
: name_(n), proc_(0), ports_(po)
{
@@ -1790,6 +2293,41 @@ void NetUDP::set_initial(char val)
init_ = val;
}
Design:: Design()
: errors(0), signals_(0), nodes_(0), procs_(0), lcounter_(0)
{
}
Design::~Design()
{
}
NetScope* Design::make_root_scope(const string&root)
{
NetScope*scope = new NetScope(root);
scopes_[root] = scope;
return scope;
}
NetScope* Design::make_scope(const string&path,
NetScope::TYPE t,
const string&name)
{
string npath = path + "." + name;
NetScope*scope = new NetScope(npath, t);
scopes_[npath] = scope;
return scope;
}
NetScope* Design::find_scope(const string&key)
{
map<string,NetScope*>::const_iterator tmp = scopes_.find(key);
if (tmp == scopes_.end())
return 0;
else
return (*tmp).second;
}
void Design::set_parameter(const string&key, NetExpr*expr)
{
parameters_[key] = expr;
@@ -1898,13 +2436,26 @@ void Design::add_memory(NetMemory*mem)
memories_[mem->name()] = mem;
}
NetMemory* Design::find_memory(const string&key)
NetMemory* Design::find_memory(const string&path, const string&name)
{
map<string,NetMemory*>::const_iterator cur = memories_.find(key);
if (cur == memories_.end())
return 0;
string root = path;
return (*cur).second;
for (;;) {
string fulname = root + "." + name;
map<string,NetMemory*>::const_iterator cur
= memories_.find(fulname);
if (cur != memories_.end())
return (*cur).second;
unsigned pos = root.rfind('.');
if (pos > root.length())
break;
root = root.substr(0, pos);
}
return 0;
}
void Design::add_function(const string&key, NetFuncDef*def)
@@ -2090,6 +2641,62 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*))
/*
* $Log: netlist.cc,v $
* Revision 1.97 1999/12/02 16:58:58 steve
* Update case comparison (Eric Aardoom).
*
* Revision 1.96 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.95 1999/11/28 01:16:18 steve
* gate outputs need to set signal values.
*
* Revision 1.94 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.93 1999/11/24 04:01:59 steve
* Detect and list scope names.
*
* Revision 1.92 1999/11/21 18:03:35 steve
* Fix expression width of memory references.
*
* Revision 1.91 1999/11/21 17:35:37 steve
* Memory name lookup handles scopes.
*
* Revision 1.90 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.89 1999/11/19 05:02:37 steve
* handle duplicate connect to a nexus.
*
* Revision 1.88 1999/11/19 03:02:25 steve
* Detect flip-flops connected to opads and turn
* them into OUTFF devices. Inprove support for
* the XNF-LCA attribute in the process.
*
* Revision 1.87 1999/11/18 03:52:19 steve
* Turn NetTmp objects into normal local NetNet objects,
* and add the nodangle functor to clean up the local
* symbols generated by elaboration and other steps.
*
* Revision 1.86 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.85 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.84 1999/11/13 03:46:52 steve
* Support the LPM_MUX in vvm.
*
* Revision 1.83 1999/11/05 04:40:40 steve
* Patch to synthesize LPM_ADD_SUB from expressions,
* Thanks to Larry Doolittle. Also handle constants
* in expressions.
*
* Synthesize adders in XNF, based on a patch from
* Larry. Accept synthesis of constants from Larry
* as is.
*
* Revision 1.82 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <[email protected]>.
@@ -2339,78 +2946,5 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*))
*
* Revision 1.15 1999/02/03 04:20:11 steve
* Parse and elaborate the Verilog CASE statement.
*
* Revision 1.14 1998/12/18 05:16:25 steve
* Parse more UDP input edge descriptions.
*
* Revision 1.13 1998/12/17 23:54:58 steve
* VVM support for small sequential UDP objects.
*
* Revision 1.12 1998/12/14 02:01:35 steve
* Fully elaborate Sequential UDP behavior.
*
* Revision 1.11 1998/12/07 04:53:17 steve
* Generate OBUF or IBUF attributes (and the gates
* to garry them) where a wire is a pad. This involved
* figuring out enough of the netlist to know when such
* was needed, and to generate new gates and signales
* to handle what's missing.
*
* Revision 1.10 1998/12/02 04:37:13 steve
* Add the nobufz function to eliminate bufz objects,
* Object links are marked with direction,
* constant propagation is more careful will wide links,
* Signal folding is aware of attributes, and
* the XNF target can dump UDP objects based on LCA
* attributes.
*
* Revision 1.9 1998/12/01 00:42:14 steve
* Elaborate UDP devices,
* Support UDP type attributes, and
* pass those attributes to nodes that
* are instantiated by elaboration,
* Put modules into a map instead of
* a simple list.
*
* Revision 1.8 1998/11/23 00:20:23 steve
* NetAssign handles lvalues as pin links
* instead of a signal pointer,
* Wire attributes added,
* Ability to parse UDP descriptions added,
* XNF generates EXT records for signals with
* the PAD attribute.
*
* Revision 1.7 1998/11/18 04:25:22 steve
* Add -f flags for generic flag key/values.
*
* Revision 1.6 1998/11/16 05:03:53 steve
* Add the sigfold function that unlinks excess
* signal nodes, and add the XNF target.
*
* Revision 1.5 1998/11/13 06:23:17 steve
* Introduce netlist optimizations with the
* cprop function to do constant propogation.
*
* Revision 1.4 1998/11/09 18:55:34 steve
* Add procedural while loops,
* Parse procedural for loops,
* Add procedural wait statements,
* Add constant nodes,
* Add XNOR logic gate,
* Make vvm output look a bit prettier.
*
* Revision 1.3 1998/11/07 19:17:10 steve
* Calculate expression widths at elaboration time.
*
* Revision 1.2 1998/11/07 17:05:05 steve
* Handle procedural conditional, and some
* of the conditional expressions.
*
* Elaborate signals and identifiers differently,
* allowing the netlist to hold signal information.
*
* Revision 1.1 1998/11/03 23:29:00 steve
* Introduce verilog to CVS.
*
*/
+272 -28
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: netlist.h,v 1.85 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: netlist.h,v 1.97 1999/12/01 06:06:16 steve Exp $"
#endif
/*
@@ -39,6 +39,7 @@ class Design;
class NetNode;
class NetProc;
class NetProcTop;
class NetScope;
class NetExpr;
class NetESignal;
class ostream;
@@ -88,18 +89,11 @@ class NetObj {
pin = pin_;
}
void next_link(NetObj*&net, unsigned&pin)
{ net = next_->node_;
pin = next_->pin_;
}
void next_link(NetObj*&net, unsigned&pin);
void next_link(const NetObj*&net, unsigned&pin) const;
void next_link(const NetObj*&net, unsigned&pin) const
{ net = next_->node_;
pin = next_->pin_;
}
Link* next_link() { return next_; }
const Link* next_link() const { return next_; }
Link* next_link();
const Link* next_link() const;
// Remove this link from the set of connected pins. The
// destructor will automatically do this if needed.
@@ -239,12 +233,14 @@ class NetNet : public NetObj, public LineInfo {
enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT };
explicit NetNet(const string&n, Type t, unsigned npins =1);
explicit NetNet(NetScope*s, const string&n, Type t, unsigned npins =1);
explicit NetNet(const string&n, Type t, long ms, long ls);
explicit NetNet(NetScope*s, const string&n, Type t, long ms, long ls);
virtual ~NetNet();
NetScope* scope();
const NetScope* scope() const;
Type type() const { return type_; }
void type(Type t) { type_ = t; }
@@ -267,6 +263,12 @@ class NetNet : public NetObj, public LineInfo {
bool local_flag() const { return local_flag_; }
void local_flag(bool f) { local_flag_ = f; }
/* NetESignal objects may reference this object. Keep a
reference count so that I keep track of them. */
void incr_eref();
void decr_eref();
unsigned get_eref() const;
verinum::V get_ival(unsigned pin) const
{ return ivalue_[pin]; }
void set_ival(unsigned pin, verinum::V val)
@@ -281,12 +283,14 @@ class NetNet : public NetObj, public LineInfo {
Design*design_;
private:
NetScope*scope_;
Type type_;
PortType port_type_;
long msb_, lsb_;
bool local_flag_;
unsigned eref_count_;
verinum::V*ivalue_;
};
@@ -317,12 +321,94 @@ class NetAddSub : public NetNode {
NetObj::Link& pin_DataB(unsigned idx);
NetObj::Link& pin_Result(unsigned idx);
const NetObj::Link& pin_DataA(unsigned idx) const;
const NetObj::Link& pin_DataB(unsigned idx) const;
const NetObj::Link& pin_Result(unsigned idx) const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual void emit_node(ostream&, struct target_t*) const;
};
/*
* This type represents the LPM_CLSHIFT device.
*/
class NetCLShift : public NetNode {
public:
NetCLShift(const string&n, unsigned width, unsigned width_dist);
~NetCLShift();
unsigned width() const;
unsigned width_dist() const;
NetObj::Link& pin_Direction();
NetObj::Link& pin_Underflow();
NetObj::Link& pin_Overflow();
NetObj::Link& pin_Data(unsigned idx);
NetObj::Link& pin_Result(unsigned idx);
NetObj::Link& pin_Distance(unsigned idx);
const NetObj::Link& pin_Direction() const;
const NetObj::Link& pin_Underflow() const;
const NetObj::Link& pin_Overflow() const;
const NetObj::Link& pin_Data(unsigned idx) const;
const NetObj::Link& pin_Result(unsigned idx) const;
const NetObj::Link& pin_Distance(unsigned idx) const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual void emit_node(ostream&, struct target_t*) const;
private:
unsigned width_;
unsigned width_dist_;
};
/*
* This class supports the LPM_COMPARE device.
*
* NOTE: This is not the same as the device used to support case
* compare. Case comparisons handle Vx and Vz values, whereas this
* device need not.
*/
class NetCompare : public NetNode {
public:
NetCompare(const string&n, unsigned width);
~NetCompare();
unsigned width() const;
NetObj::Link& pin_Aclr();
NetObj::Link& pin_Clock();
NetObj::Link& pin_AGB();
NetObj::Link& pin_AGEB();
NetObj::Link& pin_AEB();
NetObj::Link& pin_ANEB();
NetObj::Link& pin_ALB();
NetObj::Link& pin_ALEB();
NetObj::Link& pin_DataA(unsigned idx);
NetObj::Link& pin_DataB(unsigned idx);
const NetObj::Link& pin_Aclr() const;
const NetObj::Link& pin_Clock() const;
const NetObj::Link& pin_AGB() const;
const NetObj::Link& pin_AGEB() const;
const NetObj::Link& pin_AEB() const;
const NetObj::Link& pin_ANEB() const;
const NetObj::Link& pin_ALB() const;
const NetObj::Link& pin_ALEB() const;
const NetObj::Link& pin_DataA(unsigned idx) const;
const NetObj::Link& pin_DataB(unsigned idx) const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual void emit_node(ostream&, struct target_t*) const;
private:
unsigned width_;
};
/*
* This class represents an LPM_FF device. There is no literal gate
* type in Verilog that maps, but gates of this type can be inferred.
@@ -439,6 +525,50 @@ class NetMux : public NetNode {
unsigned swidth_;
};
/*
* This device represents an LPM_RAM_DQ device. The actual content is
* represented by a NetMemory object allocated elsewhere, but that
* object fixes the width and size of the device. The pin count of the
* address input is given in the constructor.
*/
class NetRamDq : public NetNode {
public:
NetRamDq(const string&name, NetMemory*mem, unsigned awid);
~NetRamDq();
unsigned width() const;
unsigned awidth() const;
unsigned size() const;
const NetMemory*mem() const;
NetObj::Link& pin_InClock();
NetObj::Link& pin_OutClock();
NetObj::Link& pin_WE();
NetObj::Link& pin_Address(unsigned idx);
NetObj::Link& pin_Data(unsigned idx);
NetObj::Link& pin_Q(unsigned idx);
const NetObj::Link& pin_InClock() const;
const NetObj::Link& pin_OutClock() const;
const NetObj::Link& pin_WE() const;
const NetObj::Link& pin_Address(unsigned idx) const;
const NetObj::Link& pin_Data(unsigned idx) const;
const NetObj::Link& pin_Q(unsigned idx) const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual void emit_node(ostream&, struct target_t*) const;
private:
friend class NetMemory;
NetMemory*mem_;
NetRamDq*next_;
unsigned awidth_;
};
/* =========
* There are cases where expressions need to be represented. The
* NetExpr class is the root of a heirarchy that serves that purpose.
@@ -493,7 +623,7 @@ class NetExpr : public LineInfo {
/*
* The expression constant is slightly special, and is sometimes
* retured from other classes that can be evaluated at compile
* returned from other classes that can be evaluated at compile
* time. This class represents constant values in expressions.
*/
class NetEConst : public NetExpr {
@@ -509,6 +639,7 @@ class NetEConst : public NetExpr {
virtual void dump(ostream&) const;
virtual NetEConst* dup_expr() const;
virtual NetNet*synthesize(Design*);
private:
verinum value_;
@@ -516,14 +647,13 @@ class NetEConst : public NetExpr {
/*
* The NetTmp object is a network that is only used momentarily by
* elaboration to carry links around. A completed netlist cannot have
* any of these within. This is a kind of wire, so it is NetNet type.
* elaboration to carry links around. A completed netlist should not
* have any of these within. This is a kind of wire, so it is NetNet type.
*/
class NetTmp : public NetNet {
public:
explicit NetTmp(unsigned npins =1)
: NetNet("@", IMPLICIT, npins) { }
explicit NetTmp(const string&name, unsigned npins =1);
};
@@ -733,6 +863,10 @@ class NetProc : public LineInfo {
// target. The target returns true if OK, false for errors.
virtual bool emit_proc(ostream&, struct target_t*) const;
// This method is called by functors that want to scan a
// process in search of matchable patterns.
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
private:
@@ -788,6 +922,7 @@ class NetAssign : public NetAssign_ {
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void emit_node(ostream&, struct target_t*) const;
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
virtual void dump_node(ostream&, unsigned ind) const;
@@ -950,6 +1085,7 @@ class NetCondit : public NetProc {
void emit_recurse_else(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
private:
@@ -1043,6 +1179,7 @@ class NetPEvent : public NetProc, public sref_back<NetPEvent,NetNEvent> {
NetProc* statement();
const NetProc* statement() const;
virtual int match_proc(struct proc_match_t*);
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
@@ -1339,6 +1476,7 @@ class NetEBAdd : public NetEBinary {
virtual bool set_width(unsigned w);
virtual NetEBAdd* dup_expr() const;
virtual NetEConst* eval_tree();
virtual NetNet* synthesize(Design*);
};
/*
@@ -1499,6 +1637,29 @@ class NetEParam : public NetExpr {
string name_;
};
/*
* This class is a special (and magical) expression node type that
* represents scope names. These can only be found as parameters to
* NetSTask objects.
*/
class NetEScope : public NetExpr {
public:
NetEScope(NetScope*);
~NetEScope();
const NetScope* scope() const;
virtual void expr_scan(struct expr_scan_t*) const;
virtual NetEScope* dup_expr() const;
virtual void dump(ostream&os) const;
private:
NetScope*scope_;
};
/*
* This node represents a system function call in an expression. The
* object contains the name of the system function, which the backend
@@ -1657,27 +1818,28 @@ class NetEMemory : public NetExpr {
* A signal shows up as a node in the netlist so that structural
* activity can invoke the expression.
*/
class NetESignal : public NetExpr, public NetNode {
class NetESignal : public NetExpr {
public:
NetESignal(NetNet*n);
NetESignal(const string&name, unsigned npins);
~NetESignal();
const string& name() const { return NetNode::name(); }
const string& name() const;
virtual bool set_width(unsigned);
virtual NetESignal* dup_expr() const;
NetNet* synthesize(Design*des);
// These methods actually reference the properties of the
// NetNet object that I point to.
unsigned pin_count() const;
NetObj::Link& pin(unsigned idx);
virtual void expr_scan(struct expr_scan_t*) const;
virtual void emit_node(ostream&, struct target_t*) const;
virtual void dump(ostream&) const;
virtual void dump_node(ostream&, unsigned ind) const;
private:
NetNet*net_;
};
/*
@@ -1710,6 +1872,30 @@ class NetESubSignal : public NetExpr {
NetExpr* idx_;
};
/*
* This object type is used to contain a logical scope within a
* design. The scope doesn't represent any executable hardware, but is
* just a handle that netlist processors can use to grab at the design.
*/
class NetScope {
public:
enum TYPE { MODULE, BEGIN_END, FORK_JOIN };
NetScope(const string&root);
NetScope(const string&path, TYPE t);
~NetScope();
TYPE type() const;
string name() const;
void dump(ostream&) const;
private:
TYPE type_;
string name_;
};
/*
* This class contains an entire design. It includes processes and a
* netlist, and can be passed around from function to function.
@@ -1717,7 +1903,9 @@ class NetESubSignal : public NetExpr {
class Design {
public:
Design() : errors(0), signals_(0), nodes_(0), procs_(0), lcounter_(0) { }
Design();
~Design();
/* The flags are a generic way of accepting command line
parameters/flags and passing them to the processing steps
@@ -1730,6 +1918,10 @@ class Design {
string get_flag(const string&key) const;
NetScope* make_root_scope(const string&name);
NetScope* make_scope(const string&path, NetScope::TYPE t,
const string&name);
NetScope* find_scope(const string&path);
// PARAMETERS
void set_parameter(const string&, NetExpr*);
@@ -1742,7 +1934,7 @@ class Design {
// Memories
void add_memory(NetMemory*);
NetMemory* find_memory(const string&name);
NetMemory* find_memory(const string&path, const string&name);
// Functions
void add_function(const string&n, NetFuncDef*);
@@ -1781,6 +1973,8 @@ class Design {
string local_symbol(const string&path);
private:
map<string,NetScope*> scopes_;
// List all the parameters in the design. This table includes
// the parameters of instantiated modules in canonical names.
map<string,NetExpr*> parameters_;
@@ -1841,6 +2035,9 @@ extern unsigned count_inputs(const NetObj::Link&pin);
extern unsigned count_outputs(const NetObj::Link&pin);
extern unsigned count_signals(const NetObj::Link&pin);
/* Find the next link that is an output into the nexus. */
extern NetObj::Link* find_next_output(NetObj::Link*lnk);
/* Find the signal connected to the given node pin. There should
always be exactly one signal. The bidx parameter get filled with
the signal index of the Net, in case it is a vector. */
@@ -1854,6 +2051,53 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.97 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
* Revision 1.96 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.95 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.94 1999/11/24 04:01:59 steve
* Detect and list scope names.
*
* Revision 1.93 1999/11/21 17:35:37 steve
* Memory name lookup handles scopes.
*
* Revision 1.92 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.91 1999/11/19 05:02:37 steve
* handle duplicate connect to a nexus.
*
* Revision 1.90 1999/11/19 03:02:25 steve
* Detect flip-flops connected to opads and turn
* them into OUTFF devices. Inprove support for
* the XNF-LCA attribute in the process.
*
* Revision 1.89 1999/11/18 03:52:19 steve
* Turn NetTmp objects into normal local NetNet objects,
* and add the nodangle functor to clean up the local
* symbols generated by elaboration and other steps.
*
* Revision 1.88 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.87 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.86 1999/11/05 04:40:40 steve
* Patch to synthesize LPM_ADD_SUB from expressions,
* Thanks to Larry Doolittle. Also handle constants
* in expressions.
*
* Synthesize adders in XNF, based on a patch from
* Larry. Accept synthesis of constants from Larry
* as is.
*
* Revision 1.85 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
+40 -7
View File
@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ident "$Id: netlist.txt,v 1.5 1999/11/02 04:55:34 steve Exp $"
#ident "$Id: netlist.txt,v 1.7 1999/11/28 23:42:02 steve Exp $"
Note that the netlist.h header contains detailed descriptions of how
@@ -114,6 +114,35 @@ and a NetProc. The NetAssign_ node has pins that represent the l-value
of the statement, and carries behavioral expressions that represent
the r-value of the assignment.
MEMORIES
The netlist form includes the NetMemory type to hold the content of a
memory. Instances of this type represent the declaration of a memory,
and occur once for each memory. References to the memory are managed
by the NetEMemory and NetAssignMem_ classes.
An instance of the NetEMemory class is created whenever a procedural
expression references a memory element. The operand is the index to
use to address (and read) the memory.
An instance of the NetAssignMem_ class is created when there is a
procedural assignment to the memory. The NetAssignMem_ object
represents the l-value reference (a write) to the memory. As with the
NetEMemory class, this is a procedural reference only.
When a memory reference appears in structural context (i.e. continuous
assignments) elaboration creates a NetRamDq. This is a LPM_RAM_DQ
device. Elaboration leaves the write control and data input pins
unconnected for now, because memories cannot appear is l-values of
continuous assignments. However, the synthesis functor may connect
signals to the write control lines to get a fully operational RAM.
By the time elaboration completes, there may be many NetAssignMem_,
NetEMemory and NetRamDq objects referencing the same NetMemory
object. Each represents a port into the memory. It is up to the
synthesis steps (and the target code) to figure out what to do with
these ports.
EXPRESSIONS
Expressions are represented as a tree of NetExpr nodes. The NetExpr
@@ -175,13 +204,10 @@ INTERACTION OF EXPRESSIONS AND STRUCTURE: NetESignal
The NetAssign_ class described above is the means for processes to
manipulate the net, but values are read from the net by NetESignal
objects. These objects are class NetExpr because they can appear in
expressions (and have width) but are also class NetNode because they
connect to and receive signals from the structural aspects of the
design.
expressions (and have width). They are not NetNode object, but hold
pointers to a NetNet object, which is used to retrieve values with the
expression is evaluated.
The pins of a NetESignal object are passive. The values at the pin are
only sampled when the process evaluates the expression that includes
the NetESignal object.
HIERARCHY IN NETLISTS
@@ -214,6 +240,13 @@ some task calls. C++ programmers recognize this as inlining a task.)
$Log: netlist.txt,v $
Revision 1.7 1999/11/28 23:42:02 steve
NetESignal object no longer need to be NetNode
objects. Let them keep a pointer to NetNet objects.
Revision 1.6 1999/11/21 00:13:09 steve
Support memories in continuous assignments.
Revision 1.5 1999/11/02 04:55:34 steve
Add the synthesize method to NetExpr to handle
synthesis of expressions, and use that method
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 1999Stephen 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)
#ident "$Id: nodangle.cc,v 1.2 1999/11/28 23:42:02 steve Exp $"
#endif
/*
* This functor scans the design looking for dangling objects and
* excess local signals. These deletions are not necessarily required
* for proper functioning of anything, but they can clean up the
* appearance of design files that are generated.
*/
# include "functor.h"
# include "netlist.h"
class nodangle_f : public functor_t {
public:
void signal(Design*des, NetNet*sig);
};
void nodangle_f::signal(Design*des, NetNet*sig)
{
if (! sig->local_flag())
return;
if (sig->get_eref() > 0)
return;
/* Check to see if there is some significant signal connected
to every pin of this signal. */
unsigned significant_flags = 0;
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) {
NetObj::Link&lnk = sig->pin(idx);
for (NetObj::Link*cur = lnk.next_link()
; cur != &lnk ; cur = cur->next_link()) {
NetNet*cursig = dynamic_cast<NetNet*>(cur->get_obj());
if (cursig == 0)
continue;
if (cursig->local_flag())
continue;
significant_flags += 1;
break;
}
}
/* If every pin is connected to another significant signal,
then I can delete this one. */
if (significant_flags == sig->pin_count())
delete sig;
}
void nodangle(Design*des)
{
nodangle_f fun;
des->functor(&fun);
}
/*
* $Log: nodangle.cc,v $
* Revision 1.2 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.1 1999/11/18 03:52:20 steve
* Turn NetTmp objects into normal local NetNet objects,
* and add the nodangle functor to clean up the local
* symbols generated by elaboration and other steps.
*
*/
+21 -5
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: parse.y,v 1.74 1999/10/15 05:03:33 steve Exp $"
#ident "$Id: parse.y,v 1.76 1999/11/15 04:43:52 steve Exp $"
#endif
# include "parse_misc.h"
@@ -336,6 +336,23 @@ description
}
;
drive_strength
: '(' dr_strength0 ',' dr_strength1 ')'
| '(' dr_strength1 ',' dr_strength0 ')'
| '(' dr_strength0 ',' K_highz1 ')'
| '(' dr_strength1 ',' K_highz0 ')'
| '(' K_highz1 ',' dr_strength0 ')'
| '(' K_highz0 ',' dr_strength1 ')'
;
drive_strength_opt
: drive_strength
|
;
dr_strength0 : K_supply0 | K_strong0 | K_pull0 | K_weak0 ;
dr_strength1 : K_supply1 | K_strong1 | K_pull1 | K_weak1 ;
event_control
: '@' IDENTIFIER
{ yyerror(@1, "sorry: event control not supported.");
@@ -857,8 +874,7 @@ identifier
: IDENTIFIER
{ $$ = $1; }
| HIDENTIFIER
{ yyerror(@1, "sorry: qualified identifiers not supported.");
$$ = $1;
{ $$ = $1;
}
;
@@ -1061,8 +1077,8 @@ module_item
{ pform_make_modgates($1, $2, $3);
delete $1;
}
| K_assign delay_opt assign_list ';'
{ pform_make_pgassign_list($3, $2, @1.text, @1.first_line); }
| K_assign drive_strength_opt delay_opt assign_list ';'
{ pform_make_pgassign_list($4, $3, @1.text, @1.first_line); }
| K_assign error '=' expression ';'
| K_always statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $2);
+8 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform.cc,v 1.46 1999/09/30 01:22:37 steve Exp $"
#ident "$Id: pform.cc,v 1.47 1999/11/23 01:04:57 steve Exp $"
#endif
# include "compiler.h"
@@ -693,7 +693,10 @@ int pform_parse(const char*path, map<string,Module*>&modules,
map<string,PUdp*>&prim)
{
vl_file = path;
vl_input = fopen(path, "r");
if (strcmp(path, "-") == 0)
vl_input = stdin;
else
vl_input = fopen(path, "r");
if (vl_input == 0) {
cerr << "Unable to open " <<vl_file << "." << endl;
return 11;
@@ -714,6 +717,9 @@ int pform_parse(const char*path, map<string,Module*>&modules,
/*
* $Log: pform.cc,v $
* Revision 1.47 1999/11/23 01:04:57 steve
* A file name of - means standard input.
*
* Revision 1.46 1999/09/30 01:22:37 steve
* Handle declaration of integers (including scope) in functions.
*
+23 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sigfold.cc,v 1.2 1998/12/02 04:37:13 steve Exp $"
#ident "$Id: sigfold.cc,v 1.3 1999/11/06 04:51:11 steve Exp $"
#endif
# include "netlist.h"
@@ -83,6 +83,24 @@ static void clear_extra_signals(NetNet*net, unsigned npin)
continue;
}
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig)) {
cerr << "internal warning: sigfold found NetTmp--"
"deleting it." << endl;
// save the next link, ...
NetObj*nxt;
unsigned pnxt;
cur->pin(pin).next_link(nxt, pnxt);
// disconnect the target signal, ...
sig->pin(pin).unlink();
// And onward.
cur = nxt;
pin = pnxt;
continue;
}
// Skip the node if it has incompatible attributes.
if (! net->has_compat_attributes(*sig)) {
@@ -152,10 +170,13 @@ void sigfold(Design*des)
/*
* $Log: sigfold.cc,v $
* Revision 1.3 1999/11/06 04:51:11 steve
* Catch NetTmp objects.
*
* Revision 1.2 1998/12/02 04:37:13 steve
* Add the nobufz function to eliminate bufz objects,
* Object links are marked with direction,
* constant propagation is more careful will wide links,
* constant propagation is more careful with wide links,
* Signal folding is aware of attributes, and
* the XNF target can dump UDP objects based on LCA
* attributes.
+114 -149
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: synth.cc,v 1.2 1999/11/02 04:55:34 steve Exp $"
#ident "$Id: synth.cc,v 1.3 1999/12/01 06:06:16 steve Exp $"
#endif
/*
@@ -26,8 +26,12 @@
* is especially interesting for the sequential components such as
* flip flops and latches. As threads are transformed into components,
* the design is rewritten.
*
* Currently, this transform recognizes the following patterns:
*/
# include "functor.h"
# include "netlist.h"
/*
* This transform recognizes the following patterns:
*
* always @(posedge CLK) Q = D
* always @(negedge CLK) Q = D
@@ -39,8 +43,105 @@
* registers) and the CE must be single-bit identifiers. The generated
* device will be wide enough to accomodate Q and D.
*/
# include "functor.h"
# include "netlist.h"
class match_dff : public proc_match_t {
public:
match_dff(Design*d, NetProcTop*t)
: des_(d), top_(t), pclk_(0), nclk_(0), con_(0), ce_(0),
asn_(0), d_(0)
{ }
~match_dff() { }
void make_it();
private:
virtual int assign(NetAssign*);
virtual int condit(NetCondit*);
virtual int pevent(NetPEvent*);
Design*des_;
NetProcTop*top_;
NetPEvent*pclk_;
NetNEvent*nclk_;
NetCondit *con_;
NetNet*ce_;
NetAssign *asn_;
NetNet*d_;
};
int match_dff::assign(NetAssign*as)
{
if (!pclk_)
return 0;
if (asn_)
return 0;
asn_ = as;
d_ = asn_->rval()->synthesize(des_);
if (d_ == 0)
return 0;
return 1;
}
int match_dff::condit(NetCondit*co)
{
if (!pclk_)
return 0;
if (con_ || asn_)
return 0;
con_ = co;
if (con_->else_clause())
return 0;
ce_ = con_->expr()->synthesize(des_);
if (ce_ == 0)
return 0;
return con_->if_clause()->match_proc(this);
}
int match_dff::pevent(NetPEvent*pe)
{
if (pclk_ || con_ || asn_)
return 0;
pclk_ = pe;
// ... there must be a single event source, ...
svector<class NetNEvent*>*neb = pclk_->back_list();
if (neb == 0)
return 0;
if (neb->count() != 1) {
delete neb;
return 0;
}
nclk_ = (*neb)[0];
delete neb;
return pclk_->statement()->match_proc(this);
}
void match_dff::make_it()
{
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) {
connect(ff->pin_Data(idx), d_->pin(idx));
connect(ff->pin_Q(idx), asn_->pin(idx));
}
connect(ff->pin_Clock(), nclk_->pin(0));
if (ce_) connect(ff->pin_Enable(), ce_->pin(0));
ff->attribute("LPM_FFType", "DFF");
if (nclk_->type() == NetNEvent::NEGEDGE)
ff->attribute("Clock:LPM_Polarity", "INVERT");
des_->add_node(ff);
}
class synth_f : public functor_t {
@@ -49,20 +150,8 @@ class synth_f : public functor_t {
private:
void proc_always_(class Design*);
void proc_casn_(class Design*);
void proc_ccon_(class Design*);
// The matcher does something like a recursive descent search
// for the templates. These variables are filled in as the
// searcher finds them.
class NetProcTop*top_;
class NetPEvent *pclk_;
class NetNEvent *nclk_;
class NetCondit *con_;
class NetAssign *asn_;
NetProcTop*top_;
};
@@ -85,141 +174,14 @@ void synth_f::process(class Design*des, class NetProcTop*top)
*/
void synth_f::proc_always_(class Design*des)
{
// The statement must be a NetPEvent, ...
pclk_ = dynamic_cast<class NetPEvent*>(top_->statement());
if (pclk_ == 0)
return;
// ... there must be a single event source, ...
svector<class NetNEvent*>*neb = pclk_->back_list();
if (neb == 0)
return;
if (neb->count() != 1) {
delete neb;
return;
}
nclk_ = (*neb)[0];
delete neb;
// ... the event must be an edge, ...
switch (nclk_->type()) {
case NetNEvent::POSEDGE:
case NetNEvent::NEGEDGE:
break;
default:
return;
}
// Is this a clocked assignment?
asn_ = dynamic_cast<NetAssign*>(pclk_->statement());
if (asn_) {
proc_casn_(des);
return;
}
con_ = dynamic_cast<NetCondit*>(pclk_->statement());
if (con_) {
proc_ccon_(des);
match_dff dff_pat(des, top_);
if (top_->statement()->match_proc(&dff_pat)) {
dff_pat.make_it();
des->delete_process(top_);
return;
}
}
/*
* The process so far has been matched as:
*
* always @(posedge nclk_) asn_ = <r>;
* always @(negedge nclk_) asn_ = <r>;
*/
void synth_f::proc_casn_(class Design*des)
{
// Turn the r-value into gates.
NetNet*sig = asn_->rval()->synthesize(des);
assert(sig);
// The signal and the assignment must be the same width...
assert(asn_->pin_count() == sig->pin_count());
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
ff->attribute("LPM_FFType", "DFF");
for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) {
connect(ff->pin_Data(idx), sig->pin(idx));
connect(ff->pin_Q(idx), asn_->pin(idx));
}
switch (nclk_->type()) {
case NetNEvent::POSEDGE:
connect(ff->pin_Clock(), nclk_->pin(0));
break;
case NetNEvent::NEGEDGE:
connect(ff->pin_Clock(), nclk_->pin(0));
ff->attribute("Clock:LPM_Polarity", "INVERT");
break;
}
des->add_node(ff);
// This process is matched and replaced with a DFF. Get
// rid of the now useless NetProcTop.
des->delete_process(top_);
}
/*
* The process so far has been matched as:
*
* always @(posedge nclk_) if ...;
* always @(negedge nclk_) if ...;
*/
void synth_f::proc_ccon_(class Design*des)
{
if (con_->else_clause())
return;
asn_ = dynamic_cast<NetAssign*>(con_->if_clause());
if (asn_ == 0)
return;
NetNet*sig = asn_->rval()->synthesize(des);
assert(sig);
// The signal and the assignment must be the same width...
assert(asn_->pin_count() == sig->pin_count());
NetESignal*ce = dynamic_cast<NetESignal*>(con_->expr());
if (ce == 0)
return;
if (ce->pin_count() != 1)
return;
NetFF*ff = new NetFF(asn_->name(), asn_->pin_count());
ff->attribute("LPM_FFType", "DFF");
for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) {
connect(ff->pin_Data(idx), sig->pin(idx));
connect(ff->pin_Q(idx), asn_->pin(idx));
}
switch (nclk_->type()) {
case NetNEvent::POSEDGE:
connect(ff->pin_Clock(), nclk_->pin(0));
connect(ff->pin_Enable(), ce->pin(0));
break;
case NetNEvent::NEGEDGE:
connect(ff->pin_Clock(), nclk_->pin(0));
connect(ff->pin_Enable(), ce->pin(0));
ff->attribute("Clock:LPM_Polarity", "INVERT");
break;
}
des->add_node(ff);
// This process is matched and replaced with a DFF. Get
// rid of the now useless NetProcTop.
des->delete_process(top_);
}
void synth(Design*des)
{
@@ -229,6 +191,9 @@ void synth(Design*des)
/*
* $Log: synth.cc,v $
* Revision 1.3 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
* Revision 1.2 1999/11/02 04:55:34 steve
* Add the synthesize method to NetExpr to handle
* synthesis of expressions, and use that method
+279 -210
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: t-vvm.cc,v 1.71 1999/11/01 02:07:41 steve Exp $"
#ident "$Id: t-vvm.cc,v 1.87 1999/12/02 16:58:58 steve Exp $"
#endif
# include <iostream>
@@ -30,6 +30,13 @@
# include "netlist.h"
# include "target.h"
// Comparison for use in sorting algorithms.
struct less_verinum {
bool operator() (const verinum&left, const verinum&right)
{ return left.is_before(right); }
};
static string make_temp()
{
static unsigned counter = 0;
@@ -47,13 +54,18 @@ class target_vvm : public target_t {
target_vvm();
virtual void start_design(ostream&os, const Design*);
virtual void scope(ostream&os, const NetScope*);
virtual void signal(ostream&os, const NetNet*);
virtual void memory(ostream&os, const NetMemory*);
virtual void task_def(ostream&os, const NetTaskDef*);
virtual void func_def(ostream&os, const NetFuncDef*);
virtual void lpm_add_sub(ostream&os, const NetAddSub*);
virtual void lpm_clshift(ostream&os, const NetCLShift*);
virtual void lpm_compare(ostream&os, const NetCompare*);
virtual void lpm_ff(ostream&os, const NetFF*);
virtual void lpm_mux(ostream&os, const NetMux*);
virtual void lpm_ram_dq(ostream&os, const NetRamDq*);
virtual void logic(ostream&os, const NetLogic*);
virtual void bufz(ostream&os, const NetBUFZ*);
@@ -61,7 +73,6 @@ class target_vvm : public target_t {
virtual void net_assign_nb(ostream&os, const NetAssignNB*);
virtual void net_case_cmp(ostream&os, const NetCaseCmp*);
virtual void net_const(ostream&os, const NetConst*);
virtual void net_esignal(ostream&os, const NetESignal*);
virtual void net_event(ostream&os, const NetNEvent*);
virtual bool process(ostream&os, const NetProcTop*);
virtual void proc_assign(ostream&os, const NetAssign*);
@@ -115,6 +126,9 @@ class target_vvm : public target_t {
// handle name mapped by this.
map<string,unsigned>string_constants;
unsigned string_counter;
map<verinum,unsigned,less_verinum>number_constants;
unsigned number_counter;
};
@@ -144,15 +158,7 @@ class vvm_proc_rval : public expr_scan_t {
virtual void expr_const(const NetEConst*);
virtual void expr_concat(const NetEConcat*);
virtual void expr_ident(const NetEIdent*);
virtual void expr_memory(const NetEMemory*mem)
{
mem->index()->expr_scan(this);
string idx = make_temp();
os_ << setw(indent_) << "" << "const unsigned " <<
idx << " = " << result << ".as_unsigned();" <<
endl;
result = mangle(mem->name()) + "[" + idx + "]";
}
virtual void expr_memory(const NetEMemory*mem);
virtual void expr_signal(const NetESignal*);
virtual void expr_subsignal(const NetESubSignal*sig);
virtual void expr_ternary(const NetETernary*);
@@ -233,6 +239,13 @@ void vvm_proc_rval::expr_ident(const NetEIdent*expr)
result = mangle(expr->name());
}
void vvm_proc_rval::expr_memory(const NetEMemory*mem)
{
const string mname = mangle(mem->name());
mem->index()->expr_scan(this);
result = mname + ".get_word(" + result + ".as_unsigned())";
}
void vvm_proc_rval::expr_signal(const NetESignal*expr)
{
result = mangle(expr->name()) + "_bits";
@@ -470,8 +483,10 @@ class vvm_parm_rval : public expr_scan_t {
string result;
private:
virtual void expr_const(const NetEConst*expr);
virtual void expr_const(const NetEConst*);
virtual void expr_ident(const NetEIdent*);
virtual void expr_memory(const NetEMemory*);
virtual void expr_scope(const NetEScope*);
virtual void expr_signal(const NetESignal*);
private:
@@ -498,33 +513,40 @@ void vvm_parm_rval::expr_const(const NetEConst*expr)
return;
}
string tname = make_temp();
tgt_->defn << " vvm_bitset_t<" <<
expr->expr_width() << "> " << tname << ";" << endl;
for (unsigned idx = 0 ; idx < expr->expr_width() ; idx += 1) {
tgt_->defn << " " << tname << "[" << idx << "] = ";
switch (expr->value().get(idx)) {
case verinum::V0:
tgt_->defn << "V0";
break;
case verinum::V1:
tgt_->defn << "V1";
break;
case verinum::Vx:
tgt_->defn << "Vx";
break;
case verinum::Vz:
tgt_->defn << "Vz";
break;
unsigned&res = tgt_->number_constants[expr->value()];
if (res == 0) {
res = tgt_->number_counter ++;
unsigned width = expr->expr_width();
tgt_->init_code << " { vpip_bit_t*bits = new vpip_bit_t["
<< width << "];" << endl;
for (unsigned idx = 0 ; idx < width ; idx += 1) {
tgt_->init_code << " bits[" << idx << "] = ";
switch(expr->value().get(idx)) {
case verinum::V0:
tgt_->init_code << "V0;" << endl;
break;
case verinum::V1:
tgt_->init_code << "V1;" << endl;
break;
case verinum::Vx:
tgt_->init_code << "Vx;" << endl;
break;
case verinum::Vz:
tgt_->init_code << "Vz;" << endl;
break;
}
}
tgt_->defn << ";" << endl;
tgt_->init_code << " vpip_make_number_const("
"&number_table[" << res << "], bits, " << width <<
");" << endl;
tgt_->init_code << " }" << endl;
}
result = make_temp();
tgt_->defn << " struct __vpiHandle " << result << ";" << endl;
tgt_->defn << " vvm_make_vpi_parm(&" << result << ", &"
<< tname << ");" << endl;
result = "&" + result;
ostrstream tmp;
tmp << "&number_table[" << res << "].base" << ends;
result = tmp.str();
return;
}
void vvm_parm_rval::expr_ident(const NetEIdent*expr)
@@ -536,6 +558,17 @@ void vvm_parm_rval::expr_ident(const NetEIdent*expr)
}
}
void vvm_parm_rval::expr_memory(const NetEMemory*mem)
{
assert(mem->index() == 0);
result = string("&") + mangle(mem->name()) + ".base";
}
void vvm_parm_rval::expr_scope(const NetEScope*escope)
{
result = string("&") + mangle(escope->scope()->name()) + "_scope.base";
}
void vvm_parm_rval::expr_signal(const NetESignal*expr)
{
string res = string("&") + mangle(expr->name()) + ".base";
@@ -573,8 +606,10 @@ void target_vvm::start_design(ostream&os, const Design*mod)
process_counter = 0;
string_counter = 1;
number_counter = 1;
os << "static struct __vpiStringConst string_table[];" << endl;
os << "static struct __vpiNumberConst number_table[];" << endl;
init_code << "static void design_init(vvm_simulation&sim)" << endl;
init_code << "{" << endl;
@@ -584,10 +619,35 @@ void target_vvm::start_design(ostream&os, const Design*mod)
start_code << "{" << endl;
}
void target_vvm::scope(ostream&os, const NetScope*scope)
{
string hname = mangle(scope->name()) + "_scope";
os << "// SCOPE: " << scope->name() << endl;
os << "static struct __vpiScope " << hname << ";" << endl;
string type_code;
switch (scope->type()) {
case NetScope::MODULE:
type_code = "vpiModule";
break;
case NetScope::BEGIN_END:
type_code = "vpiNamedBegin";
break;
case NetScope::FORK_JOIN:
type_code = "vpiNamedFork";
break;
}
init_code << " vpip_make_scope(&" << hname << ", " <<
type_code << ", \"" << scope->name() << "\");" << endl;
}
void target_vvm::end_design(ostream&os, const Design*mod)
{
os << "static struct __vpiStringConst string_table[" <<
string_counter+1 << "];" << endl;
os << "static struct __vpiNumberConst number_table[" <<
number_counter+1 << "];" << endl;
defn.close();
os << "// **** Definition code" << endl;
@@ -635,6 +695,10 @@ void target_vvm::end_design(ostream&os, const Design*mod)
os << "main()" << endl << "{" << endl;
string vpi_module_path = mod->get_flag("VPI_MODULE_PATH");
if (vpi_module_path.length() > 0)
os << " vvm_set_module_path(\"" << vpi_module_path <<
"\");" << endl;
os << " vvm_load_vpi_module(\"system.vpi\");" << endl;
os << " vvm_simulation sim;" << endl;
os << " design_init(sim);" << endl;
@@ -658,6 +722,22 @@ bool target_vvm::process(ostream&os, const NetProcTop*top)
void target_vvm::signal(ostream&os, const NetNet*sig)
{
string net_name = mangle(sig->name());
os << "static vvm_bitset_t<" << sig->pin_count() << "> " <<
net_name<< "_bits; /* " << sig->name() <<
" */" << endl;
os << "static vvm_signal_t<" << sig->pin_count() << "> " <<
net_name << "(&" << net_name << "_bits);" << endl;
init_code << " vpip_make_reg(&" << net_name <<
", \"" << sig->name() << "\");" << endl;
if (const NetScope*scope = sig->scope()) {
string sname = mangle(scope->name()) + "_scope";
init_code << " vpip_attach_to_scope(&" << sname
<< ", &" << net_name << ".base);" << endl;
}
/* Scan the signals of the vector, passing the initial value
to the inputs of all the connected devices. */
@@ -667,6 +747,10 @@ void target_vvm::signal(ostream&os, const NetNet*sig)
map<string,bool>written;
init_code << " " << mangle(sig->name()) << ".init_P("
<< idx << ", V" << sig->get_ival(idx) << ");"
<< endl;
for (const NetObj::Link*lnk = sig->pin(idx).next_link()
; (*lnk) != sig->pin(idx) ; lnk = lnk->next_link()) {
@@ -696,9 +780,13 @@ void target_vvm::signal(ostream&os, const NetNet*sig)
void target_vvm::memory(ostream&os, const NetMemory*mem)
{
os << "static vvm_bitset_t<" << mem->width() << "> " <<
mangle(mem->name()) << "[" << mem->count() << "]; " <<
"/* " << mem->name() << " */" << endl;
const string mname = mangle(mem->name());
os << "static vvm_memory_t<" << mem->width() << ", " <<
mem->count() << "> " << mname << ";"
" /* " << mem->name() << " */" << endl;
init_code << " vpip_make_memory(&" << mname << ", \"" <<
mem->name() << "\", " << mem->width() << ", " <<
mem->count() << ");" << endl;
}
void target_vvm::task_def(ostream&os, const NetTaskDef*def)
@@ -792,9 +880,7 @@ void target_vvm::emit_gate_outputfun_(const NetNode*gate, unsigned gpin)
gate->pin(gpin).next_link(cur, pin);
while (cur != gate) {
if (dynamic_cast<const NetNet*>(cur)) {
// Skip signals
} else if (cur->pin(pin).get_name() != "") {
if (cur->pin(pin).get_name() != "") {
delayed << " " << mangle(cur->name()) << ".set_"
<< cur->pin(pin).get_name() << "(sim, " <<
@@ -836,6 +922,59 @@ void target_vvm::lpm_add_sub(ostream&os, const NetAddSub*gate)
}
}
void target_vvm::lpm_clshift(ostream&os, const NetCLShift*gate)
{
os << "static vvm_clshift<" << gate->width() << "," <<
gate->width_dist() << "> " << mangle(gate->name()) << ";"
<< endl;
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);
}
}
void target_vvm::lpm_compare(ostream&os, const NetCompare*gate)
{
os << "static vvm_compare<" << gate->width() << "> " <<
mangle(gate->name()) << ";" << endl;
if (gate->pin_ALB().is_linked()) {
unsigned pin = gate->pin_ALB().get_pin();
string outfun = defn_gate_outputfun_(os,gate,pin);
init_code << " " << mangle(gate->name()) <<
".config_ALB_out(&" << outfun << ");" << endl;
emit_gate_outputfun_(gate,pin);
}
if (gate->pin_ALEB().is_linked()) {
unsigned pin = gate->pin_ALEB().get_pin();
string outfun = defn_gate_outputfun_(os, gate, pin);
init_code << " " << mangle(gate->name()) <<
".config_ALEB_out(&" << outfun << ");" << endl;
emit_gate_outputfun_(gate, pin);
}
if (gate->pin_AGB().is_linked()) {
unsigned pin = gate->pin_AGB().get_pin();
string outfun = defn_gate_outputfun_(os,gate,pin);
init_code << " " << mangle(gate->name()) <<
".config_AGB_out(&" << outfun << ");" << endl;
emit_gate_outputfun_(gate,pin);
}
if (gate->pin_AGEB().is_linked()) {
unsigned pin = gate->pin_AGEB().get_pin();
string outfun = defn_gate_outputfun_(os, gate, pin);
init_code << " " << mangle(gate->name()) <<
".config_AGEB_out(&" << outfun << ");" << endl;
emit_gate_outputfun_(gate, pin);
}
}
void target_vvm::lpm_ff(ostream&os, const NetFF*gate)
{
string mname = mangle(gate->name());
@@ -851,6 +990,37 @@ void target_vvm::lpm_ff(ostream&os, const NetFF*gate)
}
}
void target_vvm::lpm_mux(ostream&os, const NetMux*mux)
{
string mname = mangle(mux->name());
os << "static vvm_mux<" << mux->width() << "," << mux->size() <<
"," << mux->sel_width() << "> " << mname << ";" << endl;
for (unsigned idx = 0 ; idx < mux->width() ; idx += 1) {
unsigned pin = mux->pin_Result(idx).get_pin();
string outfun = defn_gate_outputfun_(os, mux, pin);
init_code << " " << mangle(mux->name()) <<
".config_rout(" << idx << ", &" << outfun << ");" << endl;
emit_gate_outputfun_(mux, pin);
}
}
void target_vvm::lpm_ram_dq(ostream&os, const NetRamDq*ram)
{
string mname = mangle(ram->name());
os << "static vvm_ram_dq<" << ram->width() << "," <<
ram->awidth() << "," << ram->size() << "> " << mname <<
"(&" << mangle(ram->mem()->name()) << ");" << endl;
for (unsigned idx = 0 ; idx < ram->width() ; idx += 1) {
unsigned pin = ram->pin_Q(idx).get_pin();
string outfun = defn_gate_outputfun_(os, ram, pin);
init_code << " " << mangle(ram->name()) <<
".config_rout(" << idx << ", &" << outfun << ");" << endl;
emit_gate_outputfun_(ram, pin);
}
}
void target_vvm::logic(ostream&os, const NetLogic*gate)
{
string outfun = defn_gate_outputfun_(os, gate, 0);
@@ -860,6 +1030,9 @@ void target_vvm::logic(ostream&os, const NetLogic*gate)
os << "static vvm_and" << "<" << gate->pin_count()-1 <<
"," << gate->rise_time() << "> ";
break;
case NetLogic::BUF:
os << "static vvm_buf<" << gate->rise_time() << "> ";
break;
case NetLogic::BUFIF0:
os << "static vvm_bufif0<" << gate->rise_time() << "> ";
break;
@@ -889,6 +1062,9 @@ void target_vvm::logic(ostream&os, const NetLogic*gate)
os << "static vvm_xor" << "<" << gate->pin_count()-1 <<
"," << gate->rise_time() << "> ";
break;
default:
os << "#error \"internal ivl error:bad gate type for " <<
gate->name() << "\"" << endl;
}
os << mangle(gate->name()) << "(&" << outfun << ");" << endl;
@@ -1042,11 +1218,6 @@ void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
continue;
// Skip signals, I'll hit them when I handle the
// NetESignal nodes.
if (dynamic_cast<const NetNet*>(cur))
continue;
delayed << " " << mangle(cur->name())
<< ".set_" << lnk.get_name() << "sim_, "
<< lnk.get_inst() << ", value_[0]);" << endl;
@@ -1074,11 +1245,6 @@ void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
continue;
// Skip signals, I'll hit them when I handle the
// NetESignal nodes.
if (dynamic_cast<const NetNet*>(cur))
continue;
delayed << " " << mangle(cur->name()) <<
".set_" << lnk.get_name() << "(sim_, "
<< lnk.get_inst() << ", value_[" <<
@@ -1091,13 +1257,16 @@ void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
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_fun(vvm_simulation*, vpip_bit_t);" << endl;
"_output_" << lnk.get_name() << "_" << lnk.get_inst() <<
"(vvm_simulation*, vpip_bit_t);" << endl;
assert(gate->pin_count() == 3);
os << "static vvm_eeq" << "<" << gate->rise_time() << "> "
<< mangle(gate->name()) << "(&" << mangle(gate->name()) <<
"_output_fun);" << endl;
"_output_" << lnk.get_name() << "_" << lnk.get_inst() << ");" << endl;
emit_gate_outputfun_(gate, 0);
@@ -1138,24 +1307,6 @@ void target_vvm::net_const(ostream&os, const NetConst*gate)
emit_gate_outputfun_(gate, 0);
}
void target_vvm::net_esignal(ostream&os, const NetESignal*net)
{
bool&flag = esignal_printed_flag[net->name()];
if (flag)
return;
flag = true;
string net_name = mangle(net->name());
os << "static vvm_bitset_t<" << net->pin_count() << "> " <<
net_name<< "_bits; /* " << net->name() <<
" */" << endl;
os << "static vvm_signal_t<" << net->pin_count() << "> " <<
net_name << "(&" << net_name << "_bits);" << endl;
init_code << " vpip_make_reg(&" << net_name <<
", \"" << net->name() << "\");" << endl;
}
/*
* The net_event device is a synthetic device type--a fabrication of
* the elaboration phase. An event device receives value changes from
@@ -1255,11 +1406,6 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
continue;
// Skip signals, I'll hit them when I handle the
// NetESignal nodes.
if (dynamic_cast<const NetNet*>(cur))
continue;
// It is possible for a named device to show up
// several times in a link. This is the classic
// case with NetESignal objects, which are
@@ -1296,11 +1442,6 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
if (cur->pin(pin).get_dir() == NetObj::Link::OUTPUT)
continue;
// Skip signals, I'll hit them when I handle the
// NetESignal nodes.
if (dynamic_cast<const NetNet*>(cur))
continue;
// It is possible for a named device to show up
// several times in a link. This is the classic
// case with NetESignal objects, which are
@@ -1331,9 +1472,9 @@ void target_vvm::proc_assign_mem(ostream&os, const NetAssignMem*amem)
defn << " /* " << amem->get_line() << " */" << endl;
if (mem->width() == amem->rval()->expr_width()) {
defn << " " << mangle(mem->name())
<< "[" << index << ".as_unsigned()] = " << rval <<
";" << endl;
defn << " " << mangle(mem->name()) <<
".set_word(sim_, " << index << ".as_unsigned(), " <<
rval << ");" << endl;
} else {
assert(mem->width() <= amem->rval()->expr_width());
@@ -1344,9 +1485,8 @@ void target_vvm::proc_assign_mem(ostream&os, const NetAssignMem*amem)
defn << " " << tmp << "[" << idx << "] = " <<
rval << "[" << idx << "];" << endl;
defn << " " << mangle(mem->name())
<< "[" << index << ".as_unsigned()] = " << tmp << ";"
<< endl;
defn << " " << mangle(mem->name()) << ".set_word(sim_, "
<< index << ".as_unsigned(), " << tmp << ");" << endl;
}
}
@@ -1818,6 +1958,57 @@ extern const struct target tgt_vvm = {
};
/*
* $Log: t-vvm.cc,v $
* Revision 1.87 1999/12/02 16:58:58 steve
* Update case comparison (Eric Aardoom).
*
* Revision 1.86 1999/11/29 00:38:27 steve
* Properly initialize registers.
*
* Revision 1.85 1999/11/28 23:59:22 steve
* Remove useless tests for NetESignal.
*
* Revision 1.84 1999/11/28 23:42:03 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.83 1999/11/28 18:05:37 steve
* Set VPI_MODULE_PATH in the target code, if desired.
*
* Revision 1.82 1999/11/28 01:16:19 steve
* gate outputs need to set signal values.
*
* Revision 1.81 1999/11/28 00:56:08 steve
* Build up the lists in the scope of a module,
* and get $dumpvars to scan the scope for items.
*
* Revision 1.80 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.79 1999/11/24 04:38:49 steve
* LT and GT fixes from Eric Aardoom.
*
* Revision 1.78 1999/11/21 01:16:51 steve
* Fix coding errors handling names of logic devices,
* and add support for buf device in vvm.
*
* Revision 1.77 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.76 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.75 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.74 1999/11/13 03:46:52 steve
* Support the LPM_MUX in vvm.
*
* Revision 1.73 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.72 1999/11/06 16:00:17 steve
* Put number constants into a static table.
*
* Revision 1.71 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
@@ -1875,127 +2066,5 @@ extern const struct target tgt_vvm = {
*
* Revision 1.55 1999/10/01 03:58:37 steve
* More resilient assignment to memory location.
*
* Revision 1.54 1999/10/01 03:15:00 steve
* Rewrite vvm output to separateclass declarations
* from method definitions. This is required to allow
* for mutual referencing, for example by tasks.
*
* Revision 1.53 1999/09/30 21:26:59 steve
* Remember to declare the calee_ member.
*
* Revision 1.52 1999/09/29 18:36:04 steve
* Full case support
*
* Revision 1.51 1999/09/29 00:42:25 steve
* Comment on where binary operator came from.
*
* Revision 1.50 1999/09/28 23:45:09 steve
* Use files instead of strstreams for delayed output,
* and fix a missing ends in case output code.
*
* Revision 1.49 1999/09/28 03:11:09 steve
* save the thread class name so that behaviors in tasks have it.
*
* Revision 1.48 1999/09/28 01:53:37 steve
* Generate code for repeat concatenations.
*
* Revision 1.47 1999/09/28 01:21:27 steve
* Proper syntax for method pointers.
*
* Revision 1.46 1999/09/28 01:13:15 steve
* Support in vvm > and >= behavioral operators.
*
* Revision 1.45 1999/09/23 03:56:57 steve
* Support shift operators.
*
* Revision 1.44 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.43 1999/09/22 04:30:04 steve
* Parse and elaborate named for/join blocks.
*
* Revision 1.42 1999/09/16 04:18:15 steve
* elaborate concatenation repeats.
*
* Revision 1.41 1999/09/11 04:43:17 steve
* Support ternary and <= operators in vvm.
*
* Revision 1.40 1999/09/08 02:24:39 steve
* Empty conditionals (pmonta@imedia.com)
*
* Revision 1.39 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.38 1999/09/04 01:57:15 steve
* Generate fake adder code in vvm.
*
* Revision 1.37 1999/09/01 20:46:19 steve
* Handle recursive functions and arbitrary function
* references to other functions, properly pass
* function parameters and save function results.
*
* Revision 1.36 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.35 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
* Revision 1.34 1999/08/02 00:19:16 steve
* Get rid of excess set/init of NetESignal objects.
*
* Revision 1.33 1999/08/01 16:34:50 steve
* Parse and elaborate rise/fall/decay times
* for gates, and handle the rules for partial
* lists of times.
*
* Revision 1.32 1999/07/18 21:17:51 steve
* Add support for CE input to XNF DFF, and do
* complete cleanup of replaced design nodes.
*
* Revision 1.31 1999/07/17 03:39:11 steve
* simplified process scan for targets.
*
* Revision 1.30 1999/07/10 03:00:05 steve
* Proper initialization of registers.
*
* Revision 1.29 1999/07/10 01:02:08 steve
* Handle number constants as parameters.
*
* Revision 1.28 1999/07/07 04:20:57 steve
* Emit vvm for user defined tasks.
*
* Revision 1.27 1999/07/03 02:12:52 steve
* Elaborate user defined tasks.
*
* Revision 1.26 1999/06/24 04:21:45 steve
* Add the === and !== binary operators.
*
* Revision 1.25 1999/06/19 21:06:16 steve
* Elaborate and supprort to vvm the forever
* and repeat statements.
*
* Revision 1.24 1999/06/10 04:03:43 steve
* Do not bother trying to print lvalue name in comment.
*
* Revision 1.23 1999/06/09 03:00:06 steve
* Add support for procedural concatenation expression.
*
* Revision 1.22 1999/06/07 02:23:31 steve
* Support non-blocking assignment down to vvm.
*
* Revision 1.21 1999/05/12 04:03:19 steve
* emit NetAssignMem objects in vvm target.
*
* Revision 1.20 1999/05/03 01:51:29 steve
* Restore support for wait event control.
*
* Revision 1.19 1999/05/01 20:43:55 steve
* Handle wide events, such as @(a) where a has
* many bits in it.
*
* Add to vvm the binary ^ and unary & operators.
*
* Dump events a bit more completely.
*/
+296 -25
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: t-xnf.cc,v 1.11 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: t-xnf.cc,v 1.18 1999/11/19 03:02:25 steve Exp $"
#endif
/* XNF BACKEND
@@ -33,6 +33,12 @@
* PART record. Valid types are defined by Xilinx or the
* receiving tools.
*
* ncf=<path>
* Specify the path to a NCF file. This is an OUTPUT file into
* which the code generator will write netlist constraints that
* relate to pin assignments, CLB placement, etc. If this flag is
* not given, no NCF file will be written.
*
* WIRE ATTRIBUTES
*
* PAD = <io><n>
@@ -63,6 +69,8 @@
# include "netlist.h"
# include "target.h"
# include <fstream>
# include <strstream>
class target_xnf : public target_t {
@@ -71,19 +79,28 @@ class target_xnf : public target_t {
void end_design(ostream&os, const Design*);
void signal(ostream&os, const NetNet*);
void lpm_add_sub(ostream&os, const NetAddSub*);
void lpm_ff(ostream&os, const NetFF*);
void lpm_mux(ostream&os, const NetMux*);
void net_const(ostream&os, const NetConst*);
void logic(ostream&os, const NetLogic*);
void bufz(ostream&os, const NetBUFZ*);
void udp(ostream&os, const NetUDP*);
private:
static string mangle(const string&);
static string choose_sig_name(const NetObj::Link*lnk);
static void draw_pin(ostream&os, const string&name,
const NetObj::Link&lnk);
static void draw_sym_with_lcaname(ostream&os, string lca,
const NetNode*net);
static void draw_xor(ostream&os, const NetAddSub*, unsigned idx);
enum adder_type {FORCE0, LOWER, UPPER, DOUBLE };
static void draw_carry(ostream&os, const NetAddSub*, unsigned idx,
enum adder_type);
ofstream ncf_;
};
/*
@@ -106,6 +123,58 @@ string target_xnf::mangle(const string&name)
return result;
}
/*
* This method takes a signal and pin number as a nexus. Scan the
* nexus to decide which name to use if there are lots of attached
* signals.
*/
string target_xnf::choose_sig_name(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();
}
assert(sig);
ostrstream tmp;
tmp << mangle(sig->name());
if (sig->pin_count() > 1)
tmp << "<" << pin << ">";
tmp << ends;
return tmp.str();
}
void target_xnf::draw_pin(ostream&os, const string&name,
const NetObj::Link&lnk)
{
@@ -126,26 +195,11 @@ void target_xnf::draw_pin(ostream&os, const string&name,
type = 'O';
break;
}
unsigned cpin;
const NetObj*cur;
for (lnk.next_link(cur, cpin)
; cur->pin(cpin) != lnk
; cur->pin(cpin).next_link(cur, cpin)) {
const NetNet*sig = dynamic_cast<const NetNet*>(cur);
if (sig) {
os << " PIN, " << use_name << ", " << type << ", "
<< mangle(sig->name());
if (sig->pin_count() > 1)
os << "<" << cpin << ">";
if (inv)
os << ",,INV";
os << endl;
}
}
os << " PIN, " << use_name << ", " << type << ", " <<
choose_sig_name(&lnk);
if (inv) os << ",,INV";
os << endl;
}
static string scrape_pin_name(string&list)
@@ -171,23 +225,35 @@ void target_xnf::draw_sym_with_lcaname(ostream&os, string lca,
os << "SYM, " << mangle(net->name()) << ", " << lcaname
<< ", LIBVER=2.0.0" << endl;
for (idx = 0 ; idx < net->pin_count() ; idx += 1)
draw_pin(os, scrape_pin_name(lca), net->pin(idx));
for (idx = 0 ; idx < net->pin_count() ; idx += 1) {
string usename = scrape_pin_name(lca);
if (usename == "") continue;
draw_pin(os, usename, net->pin(idx));
}
os << "END" << endl;
}
void target_xnf::start_design(ostream&os, const Design*des)
{
string ncfpath = des->get_flag("ncf");
if (ncfpath != "")
ncf_.open(ncfpath.c_str());
os << "LCANET,6" << endl;
os << "PROG,verilog,0.2PRE,\"Icarus Verilog\"" << endl;
if (des->get_flag("part") != "")
ncf_ << "# Generated by Icarus Verilog 0.2PRE" << endl;
if (des->get_flag("part") != "") {
os << "PART," << des->get_flag("part") << endl;
ncf_ << "CONFIG PART=" << des->get_flag("part") << ";" << endl;
}
}
void target_xnf::end_design(ostream&os, const Design*)
{
os << "EOF" << endl;
ncf_.close();
}
void scrape_pad_info(string str, char&dir, unsigned&num)
@@ -257,6 +323,164 @@ void target_xnf::signal(ostream&os, const NetNet*net)
scrape_pad_info(pad, dir, num);
os << "EXT, " << mangle(net->name()) << ", " << dir
<< ", " << num << endl;
ncf_ << "# Assignment to pin " << num << " (DIR=" << dir <<
") by $attribute(" << net->name() << ", \"PAD\", \"" <<
pad << "\")" << endl;
ncf_ << "NET " << mangle(net->name()) << " LOC=P" << num << ";"
<< endl;
}
void target_xnf::draw_xor(ostream &os, const NetAddSub*gate, unsigned idx)
{
string name = mangle(gate->name());
string name_add = name;
string name_cout = name + "/COUT";
// We only need to pick up the
// carry if we are not the 0 bit. (We know it is 0).
os << "SYM, " << name_add << "<" << (idx+0) << ">, XOR, "
"LIBVER=2.0.0" << endl;
draw_pin(os, "O", gate->pin_Result(idx));
draw_pin(os, "I0", gate->pin_DataA(idx));
draw_pin(os, "I1", gate->pin_DataB(idx));
if (idx > 0) {
os << " PIN, I2, I, " << name_cout << "<" <<
idx << ">" << endl;
}
os << "END" << endl;
}
void target_xnf::draw_carry(ostream &os, const NetAddSub*gate, unsigned idx,
enum adder_type type)
{
string name = mangle(gate->name());
string name_cy4 = name + "/CY";
string name_cym = name + "/CM";
string name_cout = name + "/COUT";
os << "SYM, " << name_cy4 << "<" << idx << ">, CY4, "
"LIBVER=2.0.0" << endl;
// Less significant bit addends, if any
if ( type == LOWER || type == DOUBLE ) {
draw_pin(os, "A0", gate->pin_DataA(idx));
draw_pin(os, "B0", gate->pin_DataB(idx));
}
// More significant bit addends, if any
if ( type == UPPER || type == DOUBLE ) {
unsigned int i = (type==UPPER)?idx:(idx+1);
draw_pin(os, "A1", gate->pin_DataA(i));
draw_pin(os, "B1", gate->pin_DataB(i));
}
// Carry input
if ( type != FORCE0 && type != UPPER ) {
os << " PIN, CIN, I, " << name_cout << "<" <<
idx << ">" << endl;
}
// Connect the Cout0 to a signal so that I can connect
// it to the adder.
if ( type == LOWER || type == DOUBLE ) {
os << " PIN, COUT0, O, " << name_cout << "<" << (idx+1) <<
">" << endl;
}
// Connect the Cout, this will connect to the next Cin
if ( type == FORCE0 || type == UPPER || type == DOUBLE ) {
unsigned int to = (type==FORCE0)?(0):(idx+2);
if (type==UPPER) to=idx+1;
os << " PIN, COUT, O, " << name_cout << "<" << to <<
">" << endl;
}
// Carry In for mode UPPER comes from a strange place
if ( type == UPPER ) {
os << " PIN, A0, I, " << name_cout << "<dummy>" << endl;
}
// These are the mode inputs from the CY_xx pseudo-device
for (unsigned cn = 0 ; cn < 8 ; cn += 1) {
os << " PIN, C" << cn << ", I, " << name << "/C"
<< cn << "<" << (idx) << ">" << endl;
}
os << "END" << endl;
// Complete the dummy force used above
if ( type == UPPER ) {
os << "PWR, 0, " << name_cout << "<dummy>" << endl;
}
// On to the CY_xx pseudo-device itself
os << "SYM, " << name_cym << "<" << (idx) << ">, ";
switch (type) {
case FORCE0:
os << "CY4_37, CYMODE=FORCE-0" << endl;
break;
case LOWER:
os << "CY4_01, CYMODE=ADD-F-CI" << endl;
break;
case UPPER:
os << "CY4_03, CYMODE=ADD-G-F1" << endl;
break;
case DOUBLE:
os << "CY4_02, CYMODE=ADD-FG-CI" << endl;
break;
}
for (unsigned cn = 0 ; cn < 8 ; cn += 1) {
os << " PIN, C" << cn << ", O, " << name << "/C"
<< cn << "<" << (idx) << ">" << endl;
}
os << "END" << endl;
}
/*
* This function makes an adder out of carry logic symbols. It makes
* as many 2 bit adders as are possible, then the top bit is made into
* a 1-bit adder (with carry in) in the F unit. The low carry is
* initialized with the FORCE-0 configuration of a carry unit below
* the 0 bit. This takes up the carry logic of the CLB below, but not
* the G function.
*
* References:
* XNF 6.1 Specification
* Application note XAPP013
* Xilinx Libraries Guide, Chapter 12
*/
void target_xnf::lpm_add_sub(ostream&os, const NetAddSub*gate)
{
unsigned width = gate->width();
// Don't handle carry output yet
// assert (count_outputs(gate->pin_Cout())==0);
unsigned carry_width = width-1;
/* Make the force-0 cary mode object to initialize the bottom
bits of the carry chain. Label this with the width instead
of the bit position so that symbols don't clash. */
if (carry_width%2) {
draw_carry(os, gate, width, FORCE0);
} else {
draw_carry(os, gate, 0, UPPER);
}
/* Now make the 2 bit adders that chain from the cin
initializer and up. Save the tail bit (if there is one) for
later. */
for (unsigned idx = 1-(carry_width%2) ; idx < carry_width-1 ; idx += 2) {
draw_carry(os, gate, idx, DOUBLE);
}
/* Always have a tail bit */
draw_carry(os, gate, carry_width-1, LOWER);
for (unsigned idx = 0 ; idx < width ; ++idx) {
draw_xor(os, gate, idx);
}
}
void target_xnf::lpm_ff(ostream&os, const NetFF*net)
@@ -266,7 +490,13 @@ void target_xnf::lpm_ff(ostream&os, const NetFF*net)
// XXXX For now, only support DFF
assert(type == "DFF");
// XXXX For now, I do not now how to deal with XNF-LCA attributes.
string lcaname = net->attribute("XNF-LCA");
if (lcaname != "") {
draw_sym_with_lcaname(os, lcaname, net);
return;
}
assert(net->attribute("XNF-LCA") == "");
for (unsigned idx = 0 ; idx < net->width() ; idx += 1) {
@@ -302,7 +532,7 @@ void target_xnf::lpm_mux(ostream&os, const NetMux*net)
for (unsigned idx = 0 ; idx < net->width() ; idx += 1) {
os << "SYM, " << mangle(net->name()) << "<" << idx << ">"
os << "SYM, " << mangle(net->name()) << "<" << idx << ">,"
<< " EQN, EQN=(I0 * I2) + (~I0 * I1)" << endl;
draw_pin(os, "I0", net->pin_Sel(0));
@@ -315,6 +545,18 @@ void target_xnf::lpm_mux(ostream&os, const NetMux*net)
}
void target_xnf::net_const(ostream&os, const NetConst*c)
{
verinum::V v=c->value();
assert(v==verinum::V0 || v==verinum::V1);
const NetObj::Link& lnk = c->pin(0);
// Code parallels draw_pin above, some smart c++ guru should
// find a way to make a method out of this.
unsigned cpin;
const NetObj*cur;
os << " PWR, " << v << ", " << choose_sig_name(&lnk) << endl;
}
/*
* The logic gates I know so far can be translated directly into XNF
@@ -411,6 +653,35 @@ extern const struct target tgt_xnf = { "xnf", &target_xnf_obj };
/*
* $Log: t-xnf.cc,v $
* Revision 1.18 1999/11/19 03:02:25 steve
* Detect flip-flops connected to opads and turn
* them into OUTFF devices. Inprove support for
* the XNF-LCA attribute in the process.
*
* Revision 1.17 1999/11/17 18:52:09 steve
* Add algorithm for choosing nexus name from attached signals.
*
* Revision 1.16 1999/11/17 01:31:28 steve
* Clean up warnings that add_sub got from Alliance
*
* Revision 1.15 1999/11/06 04:51:42 steve
* Support writing some XNF things into an NCF file.
*
* Revision 1.14 1999/11/05 18:43:12 steve
* fix syntax of EQN record.
*
* Revision 1.13 1999/11/05 07:10:45 steve
* Include the obvious XOR gates in the adders.
*
* Revision 1.12 1999/11/05 04:40:40 steve
* Patch to synthesize LPM_ADD_SUB from expressions,
* Thanks to Larry Doolittle. Also handle constants
* in expressions.
*
* Synthesize adders in XNF, based on a patch from
* Larry. Accept synthesis of constants from Larry
* as is.
*
* Revision 1.11 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
+45 -8
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: target.cc,v 1.23 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: target.cc,v 1.28 1999/11/28 23:42:03 steve Exp $"
#endif
# include "target.h"
@@ -31,6 +31,10 @@ void target_t::start_design(ostream&os, const Design*)
{
}
void target_t::scope(ostream&, const NetScope*)
{
}
void target_t::signal(ostream&os, const NetNet*)
{
}
@@ -75,6 +79,18 @@ void target_t::lpm_add_sub(ostream&, const NetAddSub*)
"Unhandled NetAddSub." << endl;
}
void target_t::lpm_clshift(ostream&, const NetCLShift*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCLShift." << endl;
}
void target_t::lpm_compare(ostream&, const NetCompare*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetCompare." << endl;
}
void target_t::lpm_ff(ostream&, const NetFF*)
{
cerr << "target (" << typeid(*this).name() << "): "
@@ -87,6 +103,12 @@ void target_t::lpm_mux(ostream&, const NetMux*)
"Unhandled NetMux." << endl;
}
void target_t::lpm_ram_dq(ostream&, const NetRamDq*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetRamDq." << endl;
}
void target_t::net_assign(ostream&os, const NetAssign*)
{
}
@@ -109,13 +131,6 @@ void target_t::net_const(ostream&os, const NetConst*)
"Unhandled CONSTANT node." << endl;
}
void target_t::net_esignal(ostream&os, const NetESignal*net)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled Expression Signal node." << endl;
net->dump_node(cerr, 4);
}
void target_t::net_event(ostream&os, const NetNEvent*net)
{
cerr << "target (" << typeid(*this).name() << "): "
@@ -249,6 +264,12 @@ void expr_scan_t::expr_memory(const NetEMemory*)
"unhandled expr_memory." << endl;
}
void expr_scan_t::expr_scope(const NetEScope*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
"unhandled expr_scope." << endl;
}
void expr_scan_t::expr_signal(const NetESignal*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
@@ -287,6 +308,22 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
/*
* $Log: target.cc,v $
* Revision 1.28 1999/11/28 23:42:03 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.27 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.26 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.25 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.24 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.23 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
+25 -2
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: target.h,v 1.22 1999/11/04 03:53:26 steve Exp $"
#ident "$Id: target.h,v 1.27 1999/11/28 23:42:03 steve Exp $"
#endif
# include "netlist.h"
@@ -55,6 +55,10 @@ struct target_t {
/* Start the design. */
virtual void start_design(ostream&os, const Design*);
/* This is called once for each scope in the design, before
anything else is called. */
virtual void scope(ostream&os, const NetScope*);
/* Output a signal (called for each signal) */
virtual void signal(ostream&os, const NetNet*);
@@ -67,8 +71,11 @@ struct target_t {
/* LPM style components are handled here. */
virtual void lpm_add_sub(ostream&os, const NetAddSub*);
virtual void lpm_clshift(ostream&os, const NetCLShift*);
virtual void lpm_compare(ostream&os, const NetCompare*);
virtual void lpm_ff(ostream&os, const NetFF*);
virtual void lpm_mux(ostream&os, const NetMux*);
virtual void lpm_ram_dq(ostream&os, const NetRamDq*);
/* Output a gate (called for each gate) */
virtual void logic(ostream&os, const NetLogic*);
@@ -78,7 +85,6 @@ struct target_t {
virtual void net_assign_nb(ostream&os, const NetAssignNB*);
virtual void net_case_cmp(ostream&os, const NetCaseCmp*);
virtual void net_const(ostream&os, const NetConst*);
virtual void net_esignal(ostream&os, const NetESignal*);
virtual void net_event(ostream&os, const NetNEvent*);
/* Output a process (called for each process). It is up to the
@@ -114,6 +120,7 @@ struct expr_scan_t {
virtual void expr_concat(const NetEConcat*);
virtual void expr_ident(const NetEIdent*);
virtual void expr_memory(const NetEMemory*);
virtual void expr_scope(const NetEScope*);
virtual void expr_signal(const NetESignal*);
virtual void expr_subsignal(const NetESubSignal*);
virtual void expr_ternary(const NetETernary*);
@@ -139,6 +146,22 @@ extern const struct target *target_table[];
/*
* $Log: target.h,v $
* Revision 1.27 1999/11/28 23:42:03 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.26 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.25 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.24 1999/11/14 23:43:46 steve
* Support combinatorial comparators.
*
* Revision 1.23 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.22 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
+4 -3
View File
@@ -21,7 +21,7 @@
# Added support for functors, especially for the XNF target. <[email protected]>
# Setup variables
execPath=@bindir@
execPath=@libdir@/ivl
execIVLPP=${execPath}/ivlpp
execIVL=${execPath}/ivl
execCpp=@CXX@
@@ -41,8 +41,9 @@ flags=""
# If VPI module path aren't set up, warn at least
if test -z "${VPI_MODULE_PATH}" ; then
echo "Missing environment variable VPI_MODULE_PATH.";
echo "Warning: Missing environment variable VPI_MODULE_PATH.";
echo "To be able to execute, set VPI_MODULE_PATH to ${VPIModulePath}";
export VPI_MODULE_PATH=${VPIModulePath}
fi
# Try to extract given parameters
@@ -78,7 +79,7 @@ fi
case "$target" in
vvm) targetSuffix="" ;;
xnf) targetSuffix=".xnf"
functors="-Fsynth -Fsigfold -Fxnfio" ;;
functors="-Fxnfsyn -Fsigfold -Fxnfio" ;;
*) targetSuffix=".$target" ;;
esac
+16 -1
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: verinum.cc,v 1.11 1999/10/22 23:57:53 steve Exp $"
#ident "$Id: verinum.cc,v 1.12 1999/11/06 16:00:17 steve Exp $"
#endif
# include "verinum.h"
@@ -213,6 +213,18 @@ string verinum::as_string() const
return result;
}
bool verinum::is_before(const verinum&that) const
{
if (that.nbits_ > nbits_) return true;
if (that.nbits_ < nbits_) return false;
for (unsigned idx = nbits_ ; idx > 0 ; idx -= 1) {
if (bits_[idx-1] < that.bits_[idx-1]) return true;
if (bits_[idx-1] > that.bits_[idx-1]) return false;
}
return false;
}
bool verinum::is_defined() const
{
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) {
@@ -455,6 +467,9 @@ verinum operator - (const verinum&left, const verinum&r)
/*
* $Log: verinum.cc,v $
* Revision 1.12 1999/11/06 16:00:17 steve
* Put number constants into a static table.
*
* Revision 1.11 1999/10/22 23:57:53 steve
* do the <= in bits, not numbers.
*
+7 -1
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: verinum.h,v 1.7 1999/10/22 23:57:53 steve Exp $"
#ident "$Id: verinum.h,v 1.8 1999/11/06 16:00:17 steve Exp $"
#endif
# include <string>
@@ -63,6 +63,9 @@ class verinum {
// an ascii description instead of a number value.
bool is_string() const { return string_flag_; }
// Comparison for use in sorting algorithms.
bool is_before(const verinum&that) const;
// Individual bits can be accessed with the get and set
// methods.
V get(unsigned idx) const;
@@ -97,6 +100,9 @@ extern verinum operator - (const verinum&left, const verinum&right);
/*
* $Log: verinum.h,v $
* Revision 1.8 1999/11/06 16:00:17 steve
* Put number constants into a static table.
*
* Revision 1.7 1999/10/22 23:57:53 steve
* do the <= in bits, not numbers.
*
+2 -2
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.6 1999/10/22 23:58:13 steve Exp $"
#ident "$Id: Makefile.in,v 1.7 1999/11/07 20:33:30 steve Exp $"
#
#
SHELL = /bin/sh
@@ -52,7 +52,7 @@ all: system.vpi
$(CC) -Wall $(CPPFLAGS) -I$(srcdir) -MD -c $< -o $*.o
mv $*.d dep
O = sys_table.o sys_display.o sys_finish.o
O = sys_table.o sys_display.o sys_finish.o sys_vcd.o
system.vpi: $O
$(CC) -shared -o $@ $O
+189 -102
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sys_display.c,v 1.6 1999/10/29 03:37:22 steve Exp $"
#ident "$Id: sys_display.c,v 1.9 1999/11/07 02:25:07 steve Exp $"
#endif
# include "vpi_user.h"
@@ -26,68 +26,28 @@
# include <ctype.h>
# include <stdlib.h>
static void format_binary(vpiHandle argv, int fsize)
{
s_vpi_value value;
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
struct strobe_cb_info {
char*name;
vpiHandle*items;
unsigned nitems;
};
value.format = vpiBinStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
{
vpiHandle item;
unsigned nitems = 1;
vpiHandle*items = malloc(sizeof(vpiHandle));
items[0] = vpi_scan(argv);
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
items = realloc(items, (nitems+1)*sizeof(vpiHandle));
items[nitems] = item;
nitems += 1;
}
info->nitems = nitems;
info->items = items;
}
static void format_octal(vpiHandle argv, int fsize)
{
s_vpi_value value;
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
value.format = vpiOctStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
}
static void format_decimal(vpiHandle argv, int fsize)
{
s_vpi_value value;
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
value.format = vpiDecStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
}
static void format_hex(vpiHandle argv, int fsize)
{
s_vpi_value value;
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
value.format = vpiHexStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
}
static void format_m(vpiHandle argv, int fsize)
{
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
vpi_printf("%s", vpi_get_str(vpiFullName, item));
}
static void format_time(vpiHandle argv, int fsize)
{
s_vpi_value value;
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
value.format = vpiDecStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
}
/*
* If $display discovers a string as a parameter, this function is
@@ -95,11 +55,16 @@ static void format_time(vpiHandle argv, int fsize)
* well so that I can look for arguments as I move forward through the
* string.
*/
static void format(s_vpi_value*fmt, vpiHandle argv)
static int format_str(char*fmt, int argc, vpiHandle*argv)
{
s_vpi_value value;
char buf[256];
char*cp = fmt->value.str;
assert(fmt->value.str);
char*cp = fmt;
int idx;
assert(fmt);
idx = 0;
while (*cp) {
size_t cnt = strcspn(cp, "%\\");
@@ -123,33 +88,44 @@ static void format(s_vpi_value*fmt, vpiHandle argv)
break;
case 'b':
case 'B':
format_binary(argv, fsize);
value.format = vpiBinStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case 'd':
case 'D':
format_decimal(argv, fsize);
value.format = vpiDecStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case 'h':
case 'H':
case 'x':
case 'X':
format_hex(argv, fsize);
value.format = vpiHexStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case 'm':
format_m(argv, fsize);
vpi_printf("%s", vpi_get_str(vpiFullName, argv[idx]));
idx += 1;
cp += 1;
break;
case 'o':
case 'O':
format_octal(argv, fsize);
value.format = vpiOctStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case 't':
case 'T':
format_time(argv, fsize);
value.format = vpiDecStrVal;
vpi_get_value(argv[idx++], &value);
vpi_printf("%s", value.value.str);
cp += 1;
break;
case '%':
@@ -178,17 +154,17 @@ static void format(s_vpi_value*fmt, vpiHandle argv)
}
}
}
return idx;
}
static int sys_display_calltf(char *name)
static void do_display(struct strobe_cb_info*info)
{
s_vpi_value value;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
int idx;
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item;
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
for (idx = 0 ; idx < info->nitems ; idx += 1) {
vpiHandle item = info->items[idx];
switch (vpi_get(vpiType, item)) {
@@ -197,17 +173,16 @@ static int sys_display_calltf(char *name)
break;
case vpiConstant:
value.format = vpiObjTypeVal;
vpi_get_value(item, &value);
switch (value.format) {
case vpiStringVal:
format(&value, argv);
break;
case vpiSuppressVal:
break;
default:
vpi_printf("?");
break;
if (vpi_get(vpiConstType, item) == vpiStringConst) {
value.format = vpiStringVal;
vpi_get_value(item, &value);
idx += format_str(value.value.str,
info->nitems-idx-1,
info->items+idx+1);
} else {
value.format = vpiBinStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
}
break;
@@ -229,6 +204,20 @@ static int sys_display_calltf(char *name)
break;
}
}
}
static int sys_display_calltf(char *name)
{
struct strobe_cb_info info;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
array_from_iterator(&info, argv);
do_display(&info);
free(info.items);
if (strcmp(name,"$display") == 0)
vpi_printf("\n");
@@ -236,9 +225,26 @@ static int sys_display_calltf(char *name)
return 0;
}
/*
* The strobe implementation takes the parameter handles that are
* passed to the calltf and puts them in to an array for safe
* keeping. That array (and other bookkeeping) is passed, via the
* struct_cb_info object, to the REadOnlySych function strobe_cb,
* where it is use to perform the actual formatting and printing.
*/
static int strobe_cb(p_cb_data cb)
{
vpi_printf("%s NOT IMPLEMENTED YET\n", cb->user_data);
struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data;
do_display(info);
vpi_printf("\n");
free(info->name);
free(info->items);
free(info);
return 0;
}
@@ -247,6 +253,15 @@ static int sys_strobe_calltf(char*name)
struct t_cb_data cb;
struct t_vpi_time time;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
struct strobe_cb_info*info = calloc(1, sizeof(struct strobe_cb_info));
array_from_iterator(info, argv);
info->name = strdup(name);
time.type = vpiSimTime;
time.low = 0;
time.high = 0;
@@ -255,40 +270,103 @@ static int sys_strobe_calltf(char*name)
cb.cb_rtn = strobe_cb;
cb.time = &time;
cb.obj = 0;
cb.user_data = name;
cb.user_data = (char*)info;
vpi_register_cb(&cb);
return 0;
}
/*
* The $monitor system task works by managing these static variables,
* and the cbValueChange callbacks associated with registers and
* nets. Note that it is proper to keep the state in static variables
* because there can only be one monitor at a time pending (even
* though that monitor may be watching many variables).
*/
static struct strobe_cb_info monitor_info = { 0, 0, 0 };
static int monitor_scheduled = 0;
static vpiHandle *monitor_callbacks = 0;
static int monitor_cb_2(p_cb_data cb)
{
do_display(&monitor_info);
vpi_printf("\n");
monitor_scheduled = 0;
return 0;
}
static int monitor_cb_1(p_cb_data cause)
{
struct t_cb_data cb;
struct t_vpi_time time;
/* Reschedule this event so that it happens for the next
trigger on this variable. */
cb = *cause;
vpi_register_cb(&cb);
if (monitor_scheduled) return 0;
/* This this action caused the first trigger, then schedule
the monitor to happen at the end of the time slice and mark
it as scheduled. */
monitor_scheduled += 1;
time.type = vpiSimTime;
time.low = 0;
time.high = 0;
cb.reason = cbReadOnlySynch;
cb.cb_rtn = monitor_cb_2;
cb.time = &time;
cb.obj = 0;
vpi_register_cb(&cb);
return 0;
}
static int sys_monitor_calltf(char*name)
{
unsigned idx;
struct t_cb_data cb;
struct t_vpi_time time;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item;
if (monitor_callbacks) {
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1)
if (monitor_callbacks[idx])
vpi_remove_cb(monitor_callbacks[idx]);
free(monitor_callbacks);
monitor_callbacks = 0;
free(monitor_info.items);
free(monitor_info.name);
monitor_info.items = 0;
monitor_info.nitems = 0;
monitor_info.name = 0;
}
array_from_iterator(&monitor_info, argv);
monitor_info.name = strdup(name);
monitor_callbacks = calloc(monitor_info.nitems, sizeof(vpiHandle));
time.type = vpiSuppressTime;
cb.reason = cbValueChange;
cb.cb_rtn = monitor_cb_1;
cb.time = &time;
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) {
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
switch (vpi_get(vpiType, item)) {
switch (vpi_get(vpiType, monitor_info.items[idx])) {
case vpiNet:
case vpiReg:
cb.reason = cbValueChange;
cb.cb_rtn = strobe_cb;
cb.time = &time;
cb.obj = item;
cb.user_data = name;
vpi_register_cb(&cb);
cb.obj = monitor_info.items[idx];
monitor_callbacks[idx] = vpi_register_cb(&cb);
break;
default:
break;
}
}
return 0;
@@ -334,6 +412,15 @@ void sys_display_register()
/*
* $Log: sys_display.c,v $
* Revision 1.9 1999/11/07 02:25:07 steve
* Add the $monitor implementation.
*
* Revision 1.8 1999/11/06 23:32:14 steve
* Unify display and strobe format routines.
*
* Revision 1.7 1999/11/06 22:16:50 steve
* Get the $strobe task working.
*
* Revision 1.6 1999/10/29 03:37:22 steve
* Support vpiValueChance callbacks.
*
+6 -1
View File
@@ -17,21 +17,26 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sys_table.c,v 1.1 1999/08/15 01:23:56 steve Exp $"
#ident "$Id: sys_table.c,v 1.2 1999/11/07 20:33:30 steve Exp $"
#endif
extern void sys_finish_register();
extern void sys_display_register();
extern void sys_vcd_register();
void (*vlog_startup_routines[])() = {
sys_finish_register,
sys_display_register,
sys_vcd_register,
0
};
/*
* $Log: sys_table.c,v $
* Revision 1.2 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
+237
View File
@@ -0,0 +1,237 @@
/*
* Copyright (c) 1999 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)
#ident "$Id: sys_vcd.c,v 1.2 1999/11/28 00:56:08 steve Exp $"
#endif
/*
* This file contains the implementations of the VCD related
* funcitons.
*/
# include <vpi_user.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
static FILE*dump_file = 0;
struct vcd_info {
vpiHandle item;
vpiHandle cb;
struct t_vpi_time time;
char*ident;
struct vcd_info*next;
};
static struct vcd_info*vcd_list = 0;
unsigned long vcd_cur_time = 0;
static int variable_cb(p_cb_data cause)
{
unsigned long now = cause->time->low;
s_vpi_value value;
struct t_cb_data cb;
struct vcd_info*info = (struct vcd_info*)cause->user_data;
/* Reschedule this event so that it happens for the next
trigger on this variable. */
cb = *cause;
vpi_register_cb(&cb);
if (now != vcd_cur_time) {
fprintf(dump_file, "#%lu\n", now);
vcd_cur_time = now;
}
if (vpi_get(vpiSize, info->item) == 1) {
value.format = vpiBinStrVal;
vpi_get_value(info->item, &value);
fprintf(dump_file, "%s%s\n", value.value.str, info->ident);
} else {
value.format = vpiBinStrVal;
vpi_get_value(info->item, &value);
fprintf(dump_file, "b%s %s\n", value.value.str, info->ident);
}
return 0;
}
static int sys_dumpall_calltf(char*name)
{
return 0;
}
static int sys_dumpfile_calltf(char*name)
{
char*path;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item) {
s_vpi_value value;
if (vpi_get(vpiType, item) != vpiConstant) {
vpi_printf("ERROR: %s parameter must be a constant\n", name);
return 0;
}
if (vpi_get(vpiConstType, item) != vpiStringConst) {
vpi_printf("ERROR: %s parameter must be a constant\n", name);
return 0;
}
value.format = vpiStringVal;
vpi_get_value(item, &value);
path = strdup(value.value.str);
vpi_free_object(argv);
} else {
path = strdup("dumpfile.vcd");
}
assert(dump_file == 0);
dump_file = fopen(path, "w");
if (dump_file == 0) {
vpi_printf("ERROR: Unable to open %s for output.\n", path);
return 0;
}
free(path);
return 0;
}
static void scan_scope(unsigned depth, vpiHandle argv)
{
struct t_cb_data cb;
struct vcd_info*info;
char ident[64];
unsigned nident = 0;
vpiHandle item;
vpiHandle sublist;
cb.reason = cbValueChange;
cb.cb_rtn = variable_cb;
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
const char*type;
switch (vpi_get(vpiType, item)) {
case vpiNet:
case vpiReg:
type = "wire";
if (vpi_get(vpiType, item) == vpiReg)
type = "reg";
sprintf(ident, "<%u", nident++);
info = malloc(sizeof(*info));
info->time.type = vpiSimTime;
cb.time = &info->time;
cb.user_data = (char*)info;
cb.obj = item;
info->item = item;
info->ident = strdup(ident);
info->cb = vpi_register_cb(&cb);
info->next = vcd_list;
vcd_list = info;
fprintf(dump_file, "$var %s %u %s %s $end\n",
type, vpi_get(vpiSize, item), ident,
vpi_get_str(vpiFullName, item));
break;
case vpiModule:
sublist = vpi_iterate(vpiInternalScope, item);
if (sublist && (depth > 0))
scan_scope(depth-1, sublist);
break;
default:
vpi_printf("ERROR: $dumpvars: Unsupported parameter type\n");
}
}
}
static int sys_dumpvars_calltf(char*name)
{
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item == 0) {
vpi_printf("SORRY: %s requires arguments\n", name);
return 0;
}
assert(dump_file);
scan_scope(99, argv);
fprintf(dump_file, "$enddefinitions $end\n");
fprintf(dump_file, "#0\n");
return 0;
}
void sys_vcd_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpall";
tf_data.calltf = sys_dumpall_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpall";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpfile";
tf_data.calltf = sys_dumpfile_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpfile";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$dumpvars";
tf_data.calltf = sys_dumpvars_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$dumpvars";
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_vcd.c,v $
* Revision 1.2 1999/11/28 00:56:08 steve
* Build up the lists in the scope of a module,
* and get $dumpvars to scan the scope for items.
*
* Revision 1.1 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
*/
+25 -1
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_user.h,v 1.4 1999/10/28 00:47:25 steve Exp $"
#ident "$Id: vpi_user.h,v 1.9 1999/11/28 00:56:08 steve Exp $"
#endif
#ifdef __cplusplus
@@ -96,12 +96,18 @@ typedef struct t_vpi_value {
/* OBJECT CODES */
#define vpiConstant 7
#define vpiIterator 27
#define vpiMemory 29
#define vpiMemoryWord 30
#define vpiModule 32
#define vpiNamedBegin 33
#define vpiNamedFork 35
#define vpiNet 36
#define vpiReg 48
#define vpiSysTaskCall 57
#define vpiTimeVar 63
#define vpiSysTfCall 85
#define vpiArgument 89
#define vpiInternalScope 92
#define vpiCallback 1000
@@ -109,6 +115,7 @@ typedef struct t_vpi_value {
#define vpiType 1
#define vpiName 2
#define vpiFullName 3
#define vpiSize 4
#define vpiConstType 43
# define vpiDecConst 1
# define vpiRealConst 2
@@ -161,6 +168,7 @@ typedef struct t_cb_data {
#define cbUnresolvedSystf 24
extern vpiHandle vpi_register_cb(p_cb_data data);
extern int vpi_remove_cb(vpiHandle ref);
/*
* This function allows a vpi application to control the simulation
@@ -203,6 +211,22 @@ extern void (*vlog_startup_routines[])();
/*
* $Log: vpi_user.h,v $
* Revision 1.9 1999/11/28 00:56:08 steve
* Build up the lists in the scope of a module,
* and get $dumpvars to scan the scope for items.
*
* Revision 1.8 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.7 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.6 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
* Revision 1.5 1999/11/07 02:25:08 steve
* Add the $monitor implementation.
*
* Revision 1.4 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
+5 -5
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.10 1999/10/28 21:36:00 steve Exp $"
#ident "$Id: Makefile.in,v 1.14 1999/11/27 19:07:58 steve Exp $"
#
#
SHELL = /bin/sh
@@ -55,15 +55,15 @@ all: libvvm.a
%.o dep/%.d: %.c
@[ -d dep ] || mkdir dep
$(CC) -Wall -fno-exceptions $(CFLAGS) -MD -c $< -o $*.o
$(CC) -Wall $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_pevent.o \
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_gates.o vvm_pevent.o \
vvm_simulation.o vvm_thread.o vpip.o
P = vpi_callback.o \
vpi_const.o vpi_iter.o vpi_null.o \
vpi_priv.o vpi_signal.o vpi_simulation.o vpi_systask.o vpi_time.o
vpi_const.o vpi_iter.o vpi_memory.o vpi_null.o \
vpi_priv.o vpi_scope.o vpi_signal.o vpi_simulation.o vpi_systask.o vpi_time.o
libvvm.a: $O
rm -f $@
+18 -1
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_callback.c,v 1.3 1999/10/29 03:37:22 steve Exp $"
#ident "$Id: vpi_callback.c,v 1.4 1999/11/07 20:33:30 steve Exp $"
#endif
# include "vpi_priv.h"
@@ -40,8 +40,22 @@ static struct __vpirt vpip_callback_rt = {
*/
static void vpip_call_callback(void*cp)
{
unsigned long now;
struct __vpiCallback*rfp = (struct __vpiCallback*)cp;
assert(rfp->base.vpi_type->type_code == vpiCallback);
switch (rfp->cb_data.time->type) {
case vpiSuppressTime:
case vpiScaledRealTime: // XXXX not supported
break;
case vpiSimTime:
now = ((struct __vpiTimeVar*)vpip_sim_time())->time;
rfp->cb_data.time->low = now;
rfp->cb_data.time->high = 0;
break;
}
rfp->cb_data.cb_rtn(&rfp->cb_data);
free(rfp);
}
@@ -155,6 +169,9 @@ int vpi_remove_cb(vpiHandle ref)
/*
* $Log: vpi_callback.c,v $
* Revision 1.4 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
* Revision 1.3 1999/10/29 03:37:22 steve
* Support vpiValueChance callbacks.
*
+268 -2
View File
@@ -17,13 +17,229 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_const.c,v 1.1 1999/10/28 00:47:25 steve Exp $"
#ident "$Id: vpi_const.c,v 1.4 1999/11/06 22:16:50 steve Exp $"
#endif
# include "vpi_priv.h"
# include <assert.h>
# include <string.h>
# include <stdio.h>
/*
* This function is used in a couple places to interpret a bit string
* as a value.
*/
void vpip_bits_get_value(enum vpip_bit_t*bits, unsigned nbits, s_vpi_value*vp)
{
static char buff[1024];
char*cp;
unsigned val;
unsigned idx;
cp = buff;
switch (vp->format) {
case vpiObjTypeVal:
case vpiBinStrVal:
for (idx = 0 ; idx < nbits ; idx += 1)
switch (bits[nbits-idx-1]) {
case V0:
*cp++ = '0';
break;
case V1:
*cp++ = '1';
break;
case Vx:
*cp++ = 'x';
break;
case Vz:
*cp++ = 'z';
break;
}
vp->format = vpiBinStrVal;
break;
case vpiDecStrVal:
val = 0;
for (idx = 0 ; idx < nbits ; idx += 1) {
val *= 2;
switch (bits[nbits-idx-1]) {
case V0:
case Vx:
case Vz:
break;
case V1:
val += 1;
break;
}
}
sprintf(cp, "%u", val);
cp += strlen(cp);
break;
case vpiOctStrVal:
if (nbits%3) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = 0 ; i < nbits%3 ; i += 1) {
v *= 2;
switch (bits[nbits-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == nbits%3)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == nbits%3)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "01234567"[v];
}
for (idx = nbits%3 ; idx < nbits ; idx += 3) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = idx ; i < idx+3 ; i += 1) {
v *= 2;
switch (bits[nbits-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == 3)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == 3)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "01234567"[v];
}
break;
case vpiHexStrVal:
if (nbits%4) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = 0 ; i < nbits%4 ; i += 1) {
v *= 2;
switch (bits[nbits-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == nbits%4)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == nbits%4)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "0123456789abcdef"[v];
}
for (idx = nbits%4 ; idx < nbits ; idx += 4) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = idx ; i < idx+4 ; i += 1) {
v *= 2;
switch (bits[nbits-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == 4)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == 4)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "0123456789abcdef"[v];
}
break;
default:
*cp++ = '(';
*cp++ = '?';
*cp++ = ')';
break;
}
*cp++ = 0;
vp->value.str = buff;
}
static int string_get(int code, vpiHandle ref)
{
struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref;
assert(ref->vpi_type->type_code == vpiConstant);
switch (code) {
case vpiConstType:
return vpiStringConst;
default:
assert(0);
return 0;
}
}
static void string_value(vpiHandle ref, p_vpi_value vp)
{
struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref;
@@ -42,15 +258,46 @@ static void string_value(vpiHandle ref, p_vpi_value vp)
}
}
static int number_get(int code, vpiHandle ref)
{
struct __vpiNumberConst*rfp = (struct __vpiNumberConst*)ref;
assert(ref->vpi_type->type_code == vpiConstant);
switch (code) {
case vpiConstType:
return vpiBinaryConst;
default:
assert(0);
return 0;
}
}
static void number_value(vpiHandle ref, p_vpi_value vp)
{
struct __vpiNumberConst*rfp = (struct __vpiNumberConst*)ref;
assert(ref->vpi_type->type_code == vpiConstant);
vpip_bits_get_value(rfp->bits, rfp->nbits, vp);
}
static const struct __vpirt vpip_string_rt = {
vpiConstant,
0,
string_get,
0,
string_value,
0,
0
};
static const struct __vpirt vpip_number_rt = {
vpiConstant,
number_get,
0,
number_value,
0,
0
};
vpiHandle vpip_make_string_const(struct __vpiStringConst*ref, const char*val)
{
ref->base.vpi_type = &vpip_string_rt;
@@ -58,8 +305,27 @@ vpiHandle vpip_make_string_const(struct __vpiStringConst*ref, const char*val)
return &(ref->base);
}
vpiHandle vpip_make_number_const(struct __vpiNumberConst*ref,
const enum vpip_bit_t*bits,
unsigned nbits)
{
ref->base.vpi_type = &vpip_number_rt;
ref->bits = bits;
ref->nbits = nbits;
return &(ref->base);
}
/*
* $Log: vpi_const.c,v $
* Revision 1.4 1999/11/06 22:16:50 steve
* Get the $strobe task working.
*
* Revision 1.3 1999/11/06 16:52:16 steve
* complete value retrieval for number constants.
*
* Revision 1.2 1999/11/06 16:00:18 steve
* Put number constants into a static table.
*
* Revision 1.1 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
+91
View File
@@ -0,0 +1,91 @@
/*
* Copyright (c) 1999 Picture Elements, Inc.
* Stephen Williams (steve@picturel.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. In order to redistribute the software in
* binary form, you will need a Picture Elements Binary Software
* License.
*
* 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
* ---
* You should also have recieved a copy of the Picture Elements
* Binary Software License offer along with the source. This offer
* allows you to obtain the right to redistribute the software in
* binary (compiled) form. If you have not received it, contact
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
*/
#if !defined(WINNT)
#ident "$Id: vpi_memory.c,v 1.1 1999/11/10 02:52:24 steve Exp $"
#endif
# include "vpi_priv.h"
# include <stdlib.h>
# include <assert.h>
static int memory_get(int code, vpiHandle ref)
{
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
assert(ref->vpi_type->type_code==vpiMemory);
switch (code) {
case vpiSize:
return rfp->size;
default:
return 0;
}
}
static char* memory_get_str(int code, vpiHandle ref)
{
struct __vpiMemory*rfp = (struct __vpiMemory*)ref;
assert(ref->vpi_type->type_code==vpiMemory);
switch (code) {
case vpiFullName:
return (char*)rfp->name;
}
return 0;
}
static const struct __vpirt vpip_memory_rt = {
vpiMemory,
memory_get,
memory_get_str,
0,
0,
0
};
vpiHandle vpip_make_memory(struct __vpiMemory*ref, const char*name,
unsigned wid, unsigned siz)
{
ref->base.vpi_type = &vpip_memory_rt;
ref->name = name;
ref->bits = calloc(wid*siz, sizeof(enum vpip_bit_t));
ref->width = wid;
ref->size = siz;
return &(ref->base);
}
/*
* $Log: vpi_memory.c,v $
* Revision 1.1 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
*/
+74 -10
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_priv.h,v 1.3 1999/10/29 03:37:22 steve Exp $"
#ident "$Id: vpi_priv.h,v 1.8 1999/11/28 00:56:08 steve Exp $"
#endif
/*
@@ -37,6 +37,9 @@ extern "C" {
struct __vpirt;
enum vpip_bit_t { V0 = 0, V1, Vx, Vz };
extern void vpip_bits_get_value(enum vpip_bit_t*bits, unsigned nbits,
s_vpi_value*vp);
/*
* This structure is the very base of a vpiHandle. Every handle
* structure starts with this structure, so that the library can
@@ -76,15 +79,6 @@ struct __vpiCallback {
struct __vpiCallback*next;
};
/*
* This type is occasionally useful. Really! And while we're at it,
* create a single instance of the null object. (This is all we need.)
*/
struct __vpiNull {
struct __vpiHandle base;
};
extern struct __vpiNull vpip_null;
/*
* The vpiHandle for an iterator has this structure. The definition of
* the methods lives in vpi_iter.c
@@ -97,6 +91,45 @@ struct __vpiIterator {
unsigned next;
};
/*
* Memory is an array of bits that is accessible in N-bit chunks, with
* N being the width of a word.
*/
struct __vpiMemory {
struct __vpiHandle base;
/* The signal has a name (this points to static memory.) */
const char*name;
enum vpip_bit_t*bits;
unsigned width;
unsigned size;
};
/*
* This type is occasionally useful. Really! And while we're at it,
* create a single instance of the null object. (This is all we need.)
*/
struct __vpiNull {
struct __vpiHandle base;
};
extern struct __vpiNull vpip_null;
/*
* This type represents the handle to a Verilog scope. These include
* module instantiations and name begin-end blocks. The attach
* function is used to attach handles to the scope by the runtime
* initializaiton.
*/
struct __vpiScope {
struct __vpiHandle base;
/* The scope has a name. (this points to static memory.) */
const char*name;
/* Keep an array of internal scope items. */
struct __vpiHandle**intern;
unsigned nintern;
};
extern void vpip_attach_to_scope(struct __vpiScope*scope, vpiHandle obj);
/*
* This structure represents nets and registers. You can tell which by
* the type_code in the base. The bits member points to the actual
@@ -150,6 +183,13 @@ struct __vpiStringConst {
const char*value;
};
struct __vpiNumberConst {
struct __vpiHandle base;
enum vpip_bit_t*bits;
unsigned nbits;
};
/*
* These are methods to initialize specific handle types. Except for
* vpip_make_iterator, all the vpi_make_* functions expect the caller
@@ -158,8 +198,16 @@ struct __vpiStringConst {
*/
extern vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args);
extern vpiHandle vpip_make_net(struct __vpiSignal*ref, const char*name);
extern vpiHandle vpip_make_scope(struct __vpiScope*ref,
int type_code,
const char*name);
extern vpiHandle vpip_make_string_const(struct __vpiStringConst*ref,
const char*val);
extern vpiHandle vpip_make_number_const(struct __vpiNumberConst*ref,
const enum vpip_bit_t*bits,
unsigned nbits);
extern vpiHandle vpip_make_memory(struct __vpiMemory*ref, const char*name,
unsigned width, unsigned size);
extern vpiHandle vpip_make_reg(struct __vpiSignal*ref, const char*name);
extern vpiHandle vpip_make_time_var(struct __vpiTimeVar*ref,
const char*val);
@@ -226,6 +274,22 @@ extern int vpip_finished();
/*
* $Log: vpi_priv.h,v $
* Revision 1.8 1999/11/28 00:56:08 steve
* Build up the lists in the scope of a module,
* and get $dumpvars to scan the scope for items.
*
* Revision 1.7 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.6 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.5 1999/11/06 16:52:16 steve
* complete value retrieval for number constants.
*
* Revision 1.4 1999/11/06 16:00:18 steve
* Put number constants into a static table.
*
* Revision 1.3 1999/10/29 03:37:22 steve
* Support vpiValueChance callbacks.
*
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 1999 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)
#ident "$Id: vpi_scope.c,v 1.2 1999/11/28 00:56:08 steve Exp $"
#endif
# include "vpi_priv.h"
# include <stdlib.h>
# include <assert.h>
static vpiHandle module_iter(int code, vpiHandle obj)
{
struct __vpiScope*ref = (struct __vpiScope*)obj;
assert(obj->vpi_type->type_code == vpiModule);
switch (code) {
case vpiInternalScope:
return vpip_make_iterator(ref->nintern, ref->intern);
}
return 0;
}
static const struct __vpirt vpip_module_rt = {
vpiModule,
0,
0,
0,
0,
module_iter
};
vpiHandle vpip_make_scope(struct __vpiScope*ref, int type, const char*name)
{
ref->intern = 0;
ref->nintern = 0;
switch (type) {
case vpiModule:
ref->base.vpi_type = &vpip_module_rt;
break;
default:
assert(0);
}
return &ref->base;
}
void vpip_attach_to_scope(struct __vpiScope*ref, vpiHandle obj)
{
unsigned idx = ref->nintern++;
if (ref->intern == 0)
ref->intern = malloc(sizeof(vpiHandle));
else
ref->intern = realloc(ref->intern, sizeof(vpiHandle)*ref->nintern);
ref->intern[idx] = obj;
}
/*
* $Log: vpi_scope.c,v $
* Revision 1.2 1999/11/28 00:56:08 steve
* Build up the lists in the scope of a module,
* and get $dumpvars to scan the scope for items.
*
* Revision 1.1 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
*/
+34 -202
View File
@@ -17,19 +17,36 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_signal.c,v 1.2 1999/10/29 03:37:22 steve Exp $"
#ident "$Id: vpi_signal.c,v 1.5 1999/11/07 20:33:30 steve Exp $"
#endif
# include "vpi_priv.h"
# include <assert.h>
# include <string.h>
# include <stdio.h>
static int signal_get(int code, vpiHandle ref)
{
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
assert((ref->vpi_type->type_code==vpiNet)
|| (ref->vpi_type->type_code==vpiReg));
switch (code) {
case vpiSize:
return rfp->nbits;
default:
return 0;
}
}
static char* signal_get_str(int code, vpiHandle ref)
{
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
assert((ref->vpi_type->type_code==vpiNet)
|| (ref->vpi_type->type_code==vpiReg));
switch (code) {
case vpiFullName:
@@ -39,212 +56,18 @@ static char* signal_get_str(int code, vpiHandle ref)
return 0;
}
/*
* This function is a get_value_ method of a vpiHandle, that supports
* reading bits as a string.
*/
static void signal_get_value(vpiHandle ref, s_vpi_value*vp)
{
static char buff[1024];
char*cp;
unsigned width;
unsigned val;
unsigned idx;
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
assert((ref->vpi_type->type_code==vpiNet)
|| (ref->vpi_type->type_code==vpiReg));
assert(rfp->bits);
width = rfp->nbits;
cp = buff;
switch (vp->format) {
case vpiObjTypeVal:
case vpiBinStrVal:
for (idx = 0 ; idx < width ; idx += 1)
switch (rfp->bits[width-idx-1]) {
case V0:
*cp++ = '0';
break;
case V1:
*cp++ = '1';
break;
case Vx:
*cp++ = 'x';
break;
case Vz:
*cp++ = 'z';
break;
}
vp->format = vpiBinStrVal;
break;
case vpiDecStrVal:
val = 0;
for (idx = 0 ; idx < width ; idx += 1) {
val *= 2;
switch (rfp->bits[width-idx-1]) {
case V0:
case Vx:
case Vz:
break;
case V1:
val += 1;
break;
}
}
sprintf(cp, "%u", val);
cp += strlen(cp);
break;
case vpiOctStrVal:
if (width%3) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = 0 ; i < width%3 ; i += 1) {
v *= 2;
switch (rfp->bits[width-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == width%3)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == width%3)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "01234567"[v];
}
for (idx = width%3 ; idx < width ; idx += 3) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = idx ; i < idx+3 ; i += 1) {
v *= 2;
switch (rfp->bits[width-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == 3)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == 3)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "01234567"[v];
}
break;
case vpiHexStrVal:
if (width%4) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = 0 ; i < width%4 ; i += 1) {
v *= 2;
switch (rfp->bits[width-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == width%4)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == width%4)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "0123456789abcdef"[v];
}
for (idx = width%4 ; idx < width ; idx += 4) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
unsigned i;
for (i = idx ; i < idx+4 ; i += 1) {
v *= 2;
switch (rfp->bits[width-i-1]) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == 4)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == 4)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "0123456789abcdef"[v];
}
break;
default:
*cp++ = '(';
*cp++ = '?';
*cp++ = ')';
break;
}
*cp++ = 0;
vp->value.str = buff;
vpip_bits_get_value(rfp->bits, rfp->nbits, vp);
}
static const struct __vpirt vpip_net_rt = {
vpiNet,
0,
signal_get,
signal_get_str,
signal_get_value,
0,
@@ -261,7 +84,7 @@ vpiHandle vpip_make_net(struct __vpiSignal*ref, const char*name)
static const struct __vpirt vpip_reg_rt = {
vpiReg,
0,
signal_get,
signal_get_str,
signal_get_value,
0,
@@ -278,6 +101,15 @@ vpiHandle vpip_make_reg(struct __vpiSignal*ref, const char*name)
/*
* $Log: vpi_signal.c,v $
* Revision 1.5 1999/11/07 20:33:30 steve
* Add VCD output and related system tasks.
*
* Revision 1.4 1999/11/07 02:25:08 steve
* Add the $monitor implementation.
*
* Revision 1.3 1999/11/06 16:52:16 steve
* complete value retrieval for number constants.
*
* Revision 1.2 1999/10/29 03:37:22 steve
* Support vpiValueChance callbacks.
*
+64 -14
View File
@@ -1,7 +1,7 @@
#ifndef __vvm_H
#define __vvm_H
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-1999 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
@@ -19,11 +19,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm.h,v 1.20 1999/11/01 02:07:41 steve Exp $"
#ident "$Id: vvm.h,v 1.24 1999/12/02 03:36:01 steve Exp $"
#endif
# include <vector>
# include <string>
# include <cassert>
# include "vpi_priv.h"
@@ -38,6 +36,7 @@ class vvm_event;
class vvm_simulation;
class vvm_simulation_cycle;
class vvm_thread;
class ostream;
inline vpip_bit_t operator & (vpip_bit_t l, vpip_bit_t r)
@@ -106,6 +105,8 @@ class vvm_bits_t {
virtual ~vvm_bits_t() =0;
virtual unsigned get_width() const =0;
virtual vpip_bit_t get_bit(unsigned idx) const =0;
unsigned as_unsigned() const;
};
extern ostream& operator << (ostream&os, vpip_bit_t);
@@ -136,22 +137,15 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
}
vvm_bitset_t(const vvm_bitset_t<WIDTH>&that)
{ bits = that.bits; }
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]; }
unsigned as_unsigned() const
{ unsigned result = 0;
for (unsigned idx = WIDTH ; idx > 0 ; idx -= 1) {
result <<= 1;
if (bits[idx-1]) result |= 1;
}
return result;
}
public:
vpip_bit_t bits[WIDTH];
};
@@ -254,8 +248,64 @@ template <unsigned WIDTH> class vvm_signal_t : public __vpiSignal {
}
};
struct vvm_ram_callback {
vvm_ram_callback();
virtual ~vvm_ram_callback();
virtual void handle_write(vvm_simulation*sim, 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(vvm_simulation*sim, unsigned addr,
const vvm_bitset_t<WIDTH>&val)
{ unsigned base = WIDTH * addr;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits[base+idx] = val[idx];
call_list_(sim, addr);
}
vvm_bitset_t<WIDTH> get_word(unsigned addr) const
{ vvm_bitset_t<WIDTH> val;
unsigned base = WIDTH * addr;
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;
}
private:
vvm_ram_callback*cb_list_;
void call_list_(vvm_simulation*sim, unsigned idx)
{ for (vvm_ram_callback*cur = cb_list_; cur; cur = cur->next_)
cur->handle_write(sim, idx);
}
};
/*
* $Log: vvm.h,v $
* Revision 1.24 1999/12/02 03:36:01 steve
* shiftl and shiftr take unsized second parameter.
*
* Revision 1.23 1999/11/22 00:30:52 steve
* Detemplate some and, or and nor methods.
*
* Revision 1.22 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.21 1999/11/10 02:52:24 steve
* Create the vpiMemory handle type.
*
* Revision 1.20 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
+38 -1
View File
@@ -17,10 +17,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_bit.cc,v 1.4 1999/11/01 02:07:41 steve Exp $"
#ident "$Id: vvm_bit.cc,v 1.7 1999/12/02 03:36:01 steve Exp $"
#endif
# include "vvm.h"
# include <iostream>
ostream& operator << (ostream&os, vpip_bit_t bit)
{
@@ -68,6 +69,33 @@ vvm_bits_t::~vvm_bits_t()
{
}
unsigned vvm_bits_t::as_unsigned() const
{
unsigned result = 0;
unsigned width = get_width();
for (unsigned idx = width ; idx > 0 ; idx -= 1) {
result <<= 1;
switch (get_bit(idx-1)) {
case V0:
case Vx:
case Vz:
break;
case V1:
result |= 1;
break;
}
}
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;
@@ -114,6 +142,15 @@ 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.7 1999/12/02 03:36:01 steve
* shiftl and shiftr take unsized second parameter.
*
* Revision 1.6 1999/11/22 00:30:52 steve
* Detemplate some and, or and nor methods.
*
* 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
+12 -1
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_calltf.cc,v 1.8 1999/10/28 00:47:25 steve Exp $"
#ident "$Id: vvm_calltf.cc,v 1.9 1999/11/28 18:05:37 steve Exp $"
#endif
# include "vvm_calltf.h"
@@ -34,6 +34,13 @@
# define MAX_PATHLEN 1024
static char*module_path = 0;
void vvm_set_module_path(const char*path)
{
if (module_path) free(module_path);
module_path = strdup(path);
}
/*
* The load_vpi_module function attempts to locate and load the named
@@ -57,6 +64,7 @@ void vvm_load_vpi_module(const char*name)
{
void*mod = 0;
const char*path = getenv("VPI_MODULE_PATH");
if (path == 0) path = module_path;
if ((path == 0) || (strchr(name, '/'))) {
mod = dlopen(name, RTLD_NOW);
@@ -108,6 +116,9 @@ void vvm_load_vpi_module(const char*name)
/*
* $Log: vvm_calltf.cc,v $
* Revision 1.9 1999/11/28 18:05:37 steve
* Set VPI_MODULE_PATH in the target code, if desired.
*
* Revision 1.8 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
+5 -1
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_calltf.h,v 1.3 1999/10/28 00:47:25 steve Exp $"
#ident "$Id: vvm_calltf.h,v 1.4 1999/11/28 18:05:37 steve Exp $"
#endif
# include "vvm.h"
@@ -29,11 +29,15 @@
/*
* This function loads a vpi module by name.
*/
extern void vvm_set_module_path(const char*path);
extern void vvm_load_vpi_module(const char*path);
/*
* $Log: vvm_calltf.h,v $
* Revision 1.4 1999/11/28 18:05:37 steve
* Set VPI_MODULE_PATH in the target code, if desired.
*
* Revision 1.3 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
+6 -3
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_func.h,v 1.15 1999/10/28 00:47:25 steve Exp $"
#ident "$Id: vvm_func.h,v 1.16 1999/12/02 03:36:01 steve Exp $"
#endif
# include "vvm.h"
@@ -217,7 +217,7 @@ vvm_bitset_t<WIDTH> vvm_binop_xor(const vvm_bitset_t<WIDTH>&l,
*/
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_binop_shiftl(const vvm_bitset_t<WIDTH>&l,
const vvm_bitset_t<32>&r)
const vvm_bits_t&r)
{
vvm_bitset_t<WIDTH> result;
vvm_u32 s = r.as_unsigned();
@@ -234,7 +234,7 @@ vvm_bitset_t<WIDTH> vvm_binop_shiftl(const vvm_bitset_t<WIDTH>&l,
*/
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_binop_shiftr(const vvm_bitset_t<WIDTH>&l,
const vvm_bitset_t<32>&r)
const vvm_bits_t&r)
{
vvm_bitset_t<WIDTH> result;
vvm_u32 s = r.as_unsigned();
@@ -608,6 +608,9 @@ vvm_bitset_t<W> vvm_ternary(vpip_bit_t c, const vvm_bitset_t<W>&t,
/*
* $Log: vvm_func.h,v $
* Revision 1.16 1999/12/02 03:36:01 steve
* shiftl and shiftr take unsized second parameter.
*
* Revision 1.15 1999/10/28 00:47:25 steve
* Rewrite vvm VPI support to make objects more
* persistent, rewrite the simulation scheduler
+159
View File
@@ -0,0 +1,159 @@
/*
* Copyright (c) 1999 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
* ---
* You should also have recieved a copy of the Picture Elements
* Binary Software License offer along with the source. This offer
* allows you to obtain the right to redistribute the software in
* binary (compiled) form. If you have not received it, contact
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
*/
#if !defined(WINNT)
#ident "$Id: vvm_gates.cc,v 1.3 1999/12/02 04:54:11 steve Exp $"
#endif
# include "vvm_gates.h"
vvm_out_event::vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o)
: output_(o), sim_(s), val_(v)
{
}
vvm_out_event::~vvm_out_event()
{
}
void vvm_out_event::event_function()
{
output_(sim_, 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()
{
}
void vvm_1bit_out::output(vvm_simulation*sim, vpip_bit_t val)
{
vvm_event*ev = new vvm_out_event(sim, val, output_);
if (delay_ > 0)
sim->insert_event(delay_, ev);
else
sim->active_event(ev);
}
vpip_bit_t compute_and(const vpip_bit_t*inp, unsigned count)
{
vpip_bit_t outval = inp[0];
for (unsigned i = 1 ; i < count ; i += 1)
outval = outval & inp[i];
return outval;
}
vpip_bit_t compute_or(const vpip_bit_t*inp, unsigned count)
{
vpip_bit_t outval = inp[0];
for (unsigned i = 1 ; i < count ; i += 1)
outval = outval | inp[i];
return outval;
}
vpip_bit_t compute_nor(const vpip_bit_t*inp, unsigned count)
{
vpip_bit_t outval = inp[0];
for (unsigned i = 1 ; i < count ; i += 1)
outval = outval | inp[i];
return not(outval);
}
vpip_bit_t compute_xor(const vpip_bit_t*inp, unsigned count)
{
vpip_bit_t outval = inp[0];
for (unsigned i = 1; i < count; i++)
outval = outval ^ inp[i];
return outval;
}
vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count)
{
return not(compute_and(inp,count));
}
vpip_bit_t compute_xnor(const vpip_bit_t*inp, unsigned count)
{
return not(compute_xor(inp,count));
}
void compute_mux(vpip_bit_t*out, unsigned wid,
const vpip_bit_t*sel, unsigned swid,
const vpip_bit_t*dat, unsigned size)
{
unsigned tmp = 0;
for (unsigned idx = 0 ; idx < swid ; idx += 1)
switch (sel[idx]) {
case V0:
break;
case V1:
tmp |= (1<<idx);
break;
default:
tmp = size;
break;
}
if (tmp >= size) {
if (swid > 1) {
for (unsigned idx = 0; idx < wid ; idx += 1)
out[idx] = Vx;
} else {
const unsigned b0 = 0;
const unsigned b1 = wid;
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (dat[idx+b0] == dat[idx+b1])
out[idx] = dat[idx+b0];
else
out[idx] = Vx;
}
}
} else {
unsigned b = tmp * wid;
for (unsigned idx = 0; idx < wid ; idx += 1)
out[idx] = dat[idx+b];
}
}
/*
* $Log: vvm_gates.cc,v $
* Revision 1.3 1999/12/02 04:54:11 steve
* Handle mux sel of X, if inputs are equal.
*
* Revision 1.2 1999/11/24 04:38:49 steve
* LT and GT fixes from Eric Aardoom.
*
* Revision 1.1 1999/11/22 00:30:52 steve
* Detemplate some and, or and nor methods.
*
*/
+452 -231
View File
@@ -19,12 +19,23 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_gates.h,v 1.18 1999/11/01 02:07:41 steve Exp $"
#ident "$Id: vvm_gates.h,v 1.30 1999/12/02 16:58:58 steve Exp $"
#endif
# include "vvm.h"
# include <assert.h>
extern vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_and(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_nor(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_or(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_xor(const vpip_bit_t*inp, unsigned count);
extern vpip_bit_t compute_xnor(const vpip_bit_t*inp, unsigned count);
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
@@ -37,11 +48,11 @@ class vvm_out_event : public vvm_event {
public:
typedef void (*action_t)(vvm_simulation*, vpip_bit_t);
vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o)
: output_(o), sim_(s), val_(v) { }
void event_function()
{ output_(sim_, val_); }
vvm_out_event(vvm_simulation*s, vpip_bit_t v, action_t o);
~vvm_out_event();
void event_function();
private:
const action_t output_;
@@ -49,6 +60,18 @@ class vvm_out_event : public vvm_event {
const vpip_bit_t val_;
};
class vvm_1bit_out {
public:
vvm_1bit_out(vvm_out_event::action_t, unsigned delay);
~vvm_1bit_out();
void output(vvm_simulation*sim, vpip_bit_t);
private:
vvm_out_event::action_t output_;
unsigned delay_;
};
/*
* This template implements the LPM_ADD_SUB device type. The width of
* the device is a template parameter. The device handles addition and
@@ -111,47 +134,220 @@ template <unsigned WIDTH> class vvm_add_sub {
}
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_and {
template <unsigned WIDTH, unsigned long DELAY>
class vvm_and : private vvm_1bit_out {
public:
explicit vvm_and(vvm_out_event::action_t o)
: output_(o) { }
: vvm_1bit_out(o, DELAY) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void start(vvm_simulation*sim)
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
{ output(sim, compute_and(input_,WIDTH)); }
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
{ if (input_[idx] == val) return;
input_[idx] = val;
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
output(sim, compute_and(input_,WIDTH));
}
private:
vpip_bit_t compute_() const
{ vpip_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval & input_[i];
return outval;
vpip_bit_t input_[WIDTH];
};
template <unsigned WIDTH, unsigned WDIST> class vvm_clshift {
public:
explicit vvm_clshift()
{ dir_ = V0;
dist_val_ = WIDTH;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
data_[idx] = Vx;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
out_[idx] = 0;
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
dist_[idx] = Vx;
}
vpip_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
~vvm_clshift() { }
void init_Data(unsigned idx, vpip_bit_t val)
{ data_[idx] = val;
}
void init_Distance(unsigned idx, vpip_bit_t val)
{ dist_[idx] = val;
calculate_dist_();
}
void init_Direction(vpip_bit_t val)
{ dir_ = val; }
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (data_[idx] == val) return;
data_[idx] = val;
if ((dist_val_ + idx) >= WIDTH) return;
if ((dist_val_ + idx) < 0) return;
vvm_out_event::action_t out = out_[dist_val_+idx];
if (out == 0) return;
vvm_event*ev = new vvm_out_event(sim, val, out);
sim->active_event(ev);
}
void set_Distance(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (dist_[idx] == val) return;
dist_[idx] = val;
calculate_dist_();
compute_(sim);
}
void set_Direction(vvm_simulation*sim, unsigned, vpip_bit_t val)
{ if (dir_ == val) return;
dir_ = val;
calculate_dist_();
compute_(sim);
}
void config_rout(unsigned idx, vvm_out_event::action_t o)
{ out_[idx] = o;
}
private:
vpip_bit_t dir_;
vpip_bit_t data_[WIDTH];
vpip_bit_t dist_[WDIST];
vvm_out_event::action_t out_[WIDTH];
int dist_val_;
void calculate_dist_()
{ int tmp = 0;
for (unsigned idx = 0 ; idx < WDIST ; idx += 1)
switch (dist_[idx]) {
case V0:
break;
case V1:
tmp |= 1<<idx;
break;
default:
tmp = WIDTH;
}
if (tmp > WIDTH)
tmp = WIDTH;
else if (dir_ == V1)
tmp = -tmp;
dist_val_ = tmp;
}
void compute_(vvm_simulation*sim)
{ vvm_event*ev;
if (dist_val_ == WIDTH) {
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
if (out_[idx] == 0) continue;
ev = new vvm_out_event(sim, Vx, out_[idx]);
sim->active_event(ev);
}
return;
}
for (int idx = 0 ; idx < WIDTH ; idx += 1) {
if (out_[idx] == 0) continue;
vpip_bit_t val;
if ((idx-dist_val_) >= WIDTH) val = V0;
else if ((idx-dist_val_) < 0) val = V0;
else val = data_[idx-dist_val_];
ev = new vvm_out_event(sim, val, out_[idx]);
sim->active_event(ev);
}
}
};
template <unsigned WIDTH> class vvm_compare {
public:
explicit vvm_compare()
{ out_lt_ = 0;
out_le_ = 0;
gt_ = Vx;
lt_ = Vx;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
a_[idx] = Vx;
b_[idx] = Vx;
}
}
~vvm_compare() { }
void init_DataA(unsigned idx, vpip_bit_t val)
{ a_[idx] = val; }
void init_DataB(unsigned idx, vpip_bit_t val)
{ b_[idx] = val; }
void set_DataA(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (a_[idx] == val) return;
a_[idx] = val;
compute_(sim);
}
void set_DataB(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (b_[idx] == val) return;
b_[idx] = val;
compute_(sim);
}
void config_ALB_out(vvm_out_event::action_t o)
{ out_lt_ = o; }
void config_ALEB_out(vvm_out_event::action_t o)
{ out_le_ = o; }
void config_AGB_out(vvm_out_event::action_t o)
{ out_gt_ = o; }
void config_AGEB_out(vvm_out_event::action_t o)
{ out_ge_ = o; }
private:
vpip_bit_t a_[WIDTH];
vpip_bit_t b_[WIDTH];
vpip_bit_t gt_;
vpip_bit_t lt_;
vvm_out_event::action_t out_lt_;
vvm_out_event::action_t out_le_;
vvm_out_event::action_t out_gt_;
vvm_out_event::action_t out_ge_;
void compute_(vvm_simulation*sim)
{ vpip_bit_t gt = V0;
vpip_bit_t lt = V0;
vvm_event*ev;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
gt = greater_with_cascade(a_[idx], b_[idx], gt);
lt = less_with_cascade(a_[idx], b_[idx], lt);
}
if ((gt_ == gt) && (lt_ == lt)) return;
gt_ = gt;
lt_ = lt;
if (out_lt_) {
ev = new vvm_out_event(sim, lt_, out_lt_);
sim->active_event(ev);
}
if (out_le_) {
ev = new vvm_out_event(sim, not(gt_), out_le_);
sim->active_event(ev);
}
if (out_gt_) {
ev = new vvm_out_event(sim, gt_, out_gt_);
sim->active_event(ev);
}
if (out_ge_) {
ev = new vvm_out_event(sim, not(lt_), out_ge_);
sim->active_event(ev);
}
}
};
/*
* This class simulates the LPM flip-flop device.
* XXXX Inverted clock not yet supported.
@@ -202,70 +398,182 @@ template <unsigned WIDTH> class vvm_ff {
}
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_or {
/*
* This class supports mux devices. The width is the width of the data
* (or bus) path, SIZE is the number of alternative inputs and SELWID
* is the size (in bits) of the selector input.
*/
template <unsigned WIDTH, unsigned SIZE, unsigned SELWID> class vvm_mux {
public:
explicit vvm_mux()
{ unsigned idx;
for (idx = 0 ; idx < WIDTH ; idx += 1) out_[idx] = 0;
for (idx = 0 ; idx < WIDTH ; idx += 1) output_[idx] = Vx;
for (idx = 0 ; idx < SELWID; idx += 1) sel_[idx] = Vx;
for (idx = 0 ; idx < WIDTH*SIZE; idx += 1) input_[idx] = Vx;
}
void init_Sel(unsigned idx, vpip_bit_t val)
{ sel_[idx] = val; }
void init_Data(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void set_Sel(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (sel_[idx] == val) return;
sel_[idx] = val;
evaluate_(sim);
}
void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val) return;
input_[idx] = val;
evaluate_(sim);
}
void config_rout(unsigned idx, vvm_out_event::action_t o)
{ out_[idx] = o; }
private:
vpip_bit_t sel_[SELWID];
vpip_bit_t input_[WIDTH * SIZE];
vpip_bit_t output_[WIDTH];
vvm_out_event::action_t out_[WIDTH];
void evaluate_(vvm_simulation*sim)
{ vpip_bit_t tmp[WIDTH];
compute_mux(tmp, WIDTH, sel_, SELWID, input_, SIZE);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
if (tmp[idx] != output_[idx]) {
output_[idx] = tmp[idx];
vvm_event*ev = new vvm_out_event(sim,
output_[idx],
out_[idx]);
sim->active_event(ev);
}
}
};
template <unsigned WIDTH, unsigned long DELAY>
class vvm_or : private vvm_1bit_out {
public:
explicit vvm_or(vvm_out_event::action_t o)
: output_(o) { }
: vvm_1bit_out(o,DELAY) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void start(vvm_simulation*sim)
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
{ output(sim, compute_or(input_,WIDTH)); }
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx] = val;
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
output(sim, compute_or(input_,WIDTH));
}
private:
vpip_bit_t compute_() const
{ vpip_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval | input_[i];
return outval;
}
vpip_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_nor {
template <unsigned WIDTH, unsigned long DELAY>
class vvm_nor : private vvm_1bit_out {
public:
explicit vvm_nor(vvm_out_event::action_t o)
: output_(o) { }
: vvm_1bit_out(o, DELAY) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void start(vvm_simulation*sim)
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
{ output(sim, compute_nor(input_,WIDTH)); }
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx] = val;
output(sim, compute_nor(input_,WIDTH));
}
vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
private:
vpip_bit_t input_[WIDTH];
};
template <unsigned WIDTH, unsigned AWIDTH, unsigned SIZE>
class vvm_ram_dq : protected vvm_ram_callback {
public:
vvm_ram_dq(vvm_memory_t<WIDTH,SIZE>*mem)
: mem_(mem)
{ mem->set_callback(this);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
out_[idx] = 0;
for (unsigned idx = 0 ; idx < AWIDTH ; idx += 1)
addr_[idx] = Vx;
}
void init_Address(unsigned idx, vpip_bit_t val)
{ addr_[idx] = val; }
void set_Address(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (addr_[idx] == val) return;
addr_[idx] = val;
compute_();
send_out_(sim);
}
void handle_write(vvm_simulation*sim, unsigned idx)
{ if (idx == addr_val_) send_out_(sim); }
void config_rout(unsigned idx, vvm_out_event::action_t o)
{ out_[idx] = o; }
private:
vvm_memory_t<WIDTH,SIZE>*mem_;
vpip_bit_t addr_[AWIDTH];
vvm_out_event::action_t out_[WIDTH];
unsigned long addr_val_;
void compute_()
{ unsigned bit;
unsigned mask;
addr_val_ = 0;
for (bit = 0, mask = 1 ; bit < AWIDTH ; bit += 1, mask <<= 1)
if (addr_[bit] == V1) addr_val_ |= mask;
}
void send_out_(vvm_simulation*sim)
{ vvm_bitset_t<WIDTH>ov = mem_->get_word(addr_val_);
for (unsigned bit = 0 ; bit < WIDTH ; bit += 1)
if (out_[bit]) {
vvm_event*ev = new vvm_out_event(sim,
ov[bit],
out_[bit]);
sim->active_event(ev);
}
}
};
template <unsigned long DELAY> class vvm_buf {
public:
explicit vvm_buf(vvm_out_event::action_t o)
: output_(o)
{ }
void init_I(unsigned, vpip_bit_t) { }
void start(vvm_simulation*) { }
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
{ vpip_bit_t outval = val;
if (val == Vz) val = Vx;
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
@@ -273,14 +581,6 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_nor {
}
private:
vpip_bit_t compute_() const
{ vpip_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval | input_[i];
return not(outval);
}
vpip_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
@@ -319,112 +619,101 @@ template <unsigned long DELAY> class vvm_bufif1 {
}
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_nand {
template <unsigned WIDTH, unsigned long DELAY>
class vvm_nand : private vvm_1bit_out {
public:
explicit vvm_nand(vvm_out_event::action_t o)
: output_(o)
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
input_[idx] = V0;
}
: vvm_1bit_out(o, DELAY) { }
void init(unsigned idx, vpip_bit_t val) { input_[idx-1] = val; }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
// Set an input of the NAND gate causes a new output value to
// be calculated and an event generated to make the output
// happen. The input pins are numbered from 1 - WIDTH.
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
vpip_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval & input_[i];
void start(vvm_simulation*sim)
{ output(sim, compute_nand(input_,WIDTH)); }
vvm_event*ev = new vvm_out_event(sim, not(outval), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val) return;
input_[idx] = val;
output(sim, compute_nand(input_,WIDTH));
}
private:
vpip_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
/*
* Simple inverter buffer.
*/
template <unsigned long DELAY> class vvm_not {
template <unsigned long DELAY> class vvm_not : private vvm_1bit_out {
public:
explicit vvm_not(vvm_out_event::action_t o)
: output_(o)
{ }
: vvm_1bit_out(o, DELAY) { }
void init_I(unsigned, vpip_bit_t) { }
void start(vvm_simulation*) { }
void set_I(vvm_simulation*sim, unsigned, vpip_bit_t val)
{ vpip_bit_t outval = not(val);
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
{ output(sim, not(val)); }
private:
vvm_out_event::action_t output_;
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_xnor {
template <unsigned WIDTH, unsigned long DELAY>
class vvm_xnor : private vvm_1bit_out {
public:
explicit vvm_xnor(vvm_out_event::action_t o)
: output_(o) { }
: vvm_1bit_out(o,DELAY) { }
void init_I(unsigned idx, vpip_bit_t val) { input_[idx] = val; }
void start(vvm_simulation*sim)
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
{ output(sim,compute_xnor(input_,WIDTH)); }
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx] = val;
vpip_bit_t outval = compute_();
vvm_event*ev = new vvm_out_event(sim, outval, output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
output(sim,compute_xnor(input_,WIDTH));
}
private:
vpip_bit_t compute_() const
{ vpip_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval ^ input_[i];
outval = not(outval);
return outval;
}
vpip_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
template <unsigned WIDTH, unsigned long DELAY>
class vvm_xor : private vvm_1bit_out {
public:
explicit vvm_xor(vvm_out_event::action_t o)
: vvm_1bit_out(o,DELAY) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void start(vvm_simulation*sim)
{ output(sim,compute_xor(input_,WIDTH)); }
void set_I(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx] = val;
output(sim,compute_xor(input_,WIDTH)); }
private:
vpip_bit_t input_[WIDTH];
};
/*
* 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 {
public:
explicit vvm_eeq(vvm_out_event::action_t o)
: output_(o) { }
void init_I(unsigned idx, vpip_bit_t val)
@@ -445,47 +734,6 @@ template <unsigned WIDTH, unsigned long DELAY> class vvm_xor {
start(sim);
}
private:
vpip_bit_t compute_() const
{ vpip_bit_t outval = input_[0];
for (unsigned i = 1 ; i < WIDTH ; i += 1)
outval = outval ^ input_[i];
return outval;
}
vpip_bit_t input_[WIDTH];
vvm_out_event::action_t output_;
};
/*
* 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 {
public:
explicit vvm_eeq(vvm_out_event::action_t o)
: output_(o) { }
void init(unsigned idx, vpip_bit_t val)
{ input_[idx-1] = val; }
void start(vvm_simulation*sim)
{ vvm_event*ev = new vvm_out_event(sim, compute_(), output_);
if (DELAY > 0)
sim->insert_event(DELAY, ev);
else
sim->active_event(ev);
}
void set(vvm_simulation*sim, unsigned idx, vpip_bit_t val)
{ if (input_[idx-1] == val)
return;
input_[idx-1] = val;
start(sim);
}
private:
vpip_bit_t compute_() const
@@ -649,73 +897,46 @@ template <unsigned WIDTH> class vvm_pevent {
/*
* $Log: vvm_gates.h,v $
* Revision 1.30 1999/12/02 16:58:58 steve
* Update case comparison (Eric Aardoom).
*
* Revision 1.29 1999/12/02 04:54:11 steve
* Handle mux sel of X, if inputs are equal.
*
* Revision 1.28 1999/11/25 01:34:04 steve
* Reduce more gate templates to use vvm_1bit_out (Eric Aardoom)
*
* Revision 1.27 1999/11/24 04:38:49 steve
* LT and GT fixes from Eric Aardoom.
*
* Revision 1.26 1999/11/22 00:30:52 steve
* Detemplate some and, or and nor methods.
*
* Revision 1.25 1999/11/21 01:16:51 steve
* Fix coding errors handling names of logic devices,
* and add support for buf device in vvm.
*
* Revision 1.24 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.23 1999/11/15 00:42:31 steve
* Fixup to include right shift support.
*
* Revision 1.22 1999/11/14 23:43:46 steve
* Support combinatorial comparators.
*
* Revision 1.21 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.20 1999/11/14 18:22:12 steve
* Fix NAND gate support to use named pins.
*
* Revision 1.19 1999/11/13 03:46:52 steve
* Support the LPM_MUX in vvm.
*
* Revision 1.18 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.17 1999/10/31 20:08:24 steve
* Include subtraction in LPM_ADD_SUB device.
*
* Revision 1.16 1999/10/31 04:11:28 steve
* Add to netlist links pin name and instance number,
* and arrange in vvm for pin connections by name
* and instance number.
*
* Revision 1.15 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.14 1999/10/10 01:59:55 steve
* Structural case equals device.
*
* Revision 1.13 1999/10/09 19:24:36 steve
* NOR device.
*
* Revision 1.12 1999/07/17 03:07:27 steve
* pevent objects have initial values.
*
* Revision 1.11 1999/06/09 00:58:29 steve
* Support for binary | (Stephen Tell)
*
* Revision 1.10 1999/05/03 01:51:29 steve
* Restore support for wait event control.
*
* Revision 1.9 1999/05/01 20:43:55 steve
* Handle wide events, such as @(a) where a has
* many bits in it.
*
* Add to vvm the binary ^ and unary & operators.
*
* Dump events a bit more completely.
*
* Revision 1.8 1999/05/01 02:57:53 steve
* Handle much more complex event expressions.
*
* Revision 1.7 1999/02/15 05:52:50 steve
* Mangle that handles device instance numbers.
*
* Revision 1.6 1999/01/31 18:15:55 steve
* Missing start methods.
*
* Revision 1.5 1999/01/01 01:44:56 steve
* Support the start() method.
*
* Revision 1.4 1998/12/20 02:05:41 steve
* Function to calculate wire initial value.
*
* Revision 1.3 1998/12/17 23:54:58 steve
* VVM support for small sequential UDP objects.
*
* 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:11 steve
* Add vvm library.
*
*/
#endif
+27 -5
View File
@@ -15,11 +15,12 @@ GENERATE XNF OUTPUT -- THE SHORT STORY
The easiest way to compile for XNF output is with the "verilog"
command (man verilog) and the -X switch:
% verilog -fpart=4010e -X prog.v
% verilog -fpart=4010e -fncf=prog.ncf -X prog.v
This generates from the prog.v Verilog source file the prog.xnf
output. The verilog program arranges to call the preprocessor and the
ivl compiler with all the correct switches for generating XNF.
This generates from the prog.v Verilog source file the prog.xnf output
and the prog.ncf netlist constraints file. The verilog program
arranges to call the preprocessor and the ivl compiler with all the
correct switches for generating XNF.
XNF PADS IN VERILOG SOURCE
@@ -101,7 +102,7 @@ line. The code generator needs to know the type of part to generate
code for, so the ``-fpart=<type>'' flag is also needed. For example,
to generate code for the 4010E the command line might start out as:
ivl -txnf -fpart=4010e -Fsynth -Fsigfold -Fxnfio [...]
ivl -txnf -fpart=4010e -Fsynth -Fnodangle -Fxnfio [...]
Icarus Verilog includes the functions ``synth'' and ``xnfio'' to
perform transformations and optimizations on the design before code is
@@ -109,6 +110,19 @@ generated. The ``synth'' function matches certain behavioral constructs
to structural components, and the xnfio function generates pads and
fills the IOBs.
SUPPORTED FLAGS
-fpart=<part>
Specify the type of part to target. This string is written
literally into the PART, record of the XNF, and may also be
used to control synthesis and placement.
-fncf=<path>
Cause the code generator to write into <path> the netlist
constraints needed for controlling placement and timing. This
switch is required if pin assignments are assigned in the
Verilog source.
THE SYNTH FUNCTION
This function does synthesis transformations on the entered design,
@@ -162,6 +176,14 @@ IBUF, NOT gates cannot be absorbed as in the OPAD case.
$Log: xnf.txt,v $
Revision 1.9 1999/11/18 03:52:20 steve
Turn NetTmp objects into normal local NetNet objects,
and add the nodangle functor to clean up the local
symbols generated by elaboration and other steps.
Revision 1.8 1999/11/06 04:51:42 steve
Support writing some XNF things into an NCF file.
Revision 1.7 1999/11/03 05:18:18 steve
XNF synthesis now uses the synth functor.
+90 -11
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: xnfio.cc,v 1.5 1999/11/02 04:55:01 steve Exp $"
#ident "$Id: xnfio.cc,v 1.9 1999/11/27 19:07:58 steve Exp $"
#endif
# include "functor.h"
@@ -49,13 +49,19 @@ static bool is_a_pad(const NetNet*net)
* really lame to not do the obvious optimization.
*/
static void make_obuf(Design*des, NetNet*net)
static NetLogic* make_obuf(Design*des, NetNet*net)
{
assert(net->pin_count() == 1);
/* FIXME: If there is nothing internally driving this PAD, I
can connect the PAD to a pullup and disconnect it from the
rest of the circuit. This would save routing resources. */
if (count_outputs(net->pin(0)) <= 0) {
cerr << net->get_line() << ":warning: No outputs to OPAD: "
<< net->name() << endl;
return 0;
}
assert(count_outputs(net->pin(0)) > 0);
/* Look for an existing OBUF connected to this signal. If it
@@ -73,7 +79,7 @@ static void make_obuf(Design*des, NetNet*net)
&& (count_outputs(tmp->pin(0)) == 1)
&& (idx->get_pin() == 0) ) {
tmp->attribute("XNF-LCA", "OBUF:O,I");
return;
return tmp;
}
// Try to use an existing INV as an OBUF. Certain
@@ -86,7 +92,7 @@ static void make_obuf(Design*des, NetNet*net)
&& (count_outputs(tmp->pin(0)) == 1)
&& (idx->get_pin() == 0) ) {
tmp->attribute("XNF-LCA", "OBUF:O,~I");
return;
return tmp;
}
// Try to use an existing bufif1 as an OBUFT. Of course
@@ -98,7 +104,7 @@ static void make_obuf(Design*des, NetNet*net)
&& (count_outputs(tmp->pin(0)) == 1)
&& (idx->get_pin() == 0) ) {
tmp->attribute("XNF-LCA", "OBUFT:O,I,~T");
return;
return tmp;
}
if ((tmp->type() == NetLogic::BUFIF0)
@@ -106,7 +112,7 @@ static void make_obuf(Design*des, NetNet*net)
&& (count_outputs(tmp->pin(0)) == 1)
&& (idx->get_pin() == 0) ) {
tmp->attribute("XNF-LCA", "OBUFT:O,I,T");
return;
return tmp;
}
}
@@ -129,10 +135,64 @@ static void make_obuf(Design*des, NetNet*net)
// of the netlist, to create a ring without a signal. Detect
// this case and create a new signal.
if (count_signals(buf->pin(1)) == 0) {
NetNet*tmp = new NetNet(des->local_symbol("$"), NetNet::WIRE);
NetNet*tmp = new NetNet(0, des->local_symbol("$"), NetNet::WIRE);
tmp->local_flag(true);
connect(buf->pin(1), tmp->pin(0));
des->add_signal(tmp);
}
return buf;
}
static void absorb_OFF(Design*des, NetLogic*buf)
{
/* If the nexus connects is not a simple point-to-point link,
then I can't drag it into the IOB. Give up. */
if (count_outputs(buf->pin(1)) != 1)
return;
if (count_inputs(buf->pin(1)) != 1)
return;
/* For now, only support OUTFF. */
if (buf->type() != NetLogic::BUF)
return;
NetObj::Link*drv = find_next_output(&buf->pin(1));
assert(drv);
/* Make sure the device is a FF with width 1. */
NetFF*ff = dynamic_cast<NetFF*>(drv->get_obj());
if (ff == 0)
return;
if (ff->width() != 1)
return;
if (ff->attribute("LPM_FFType") != "DFF")
return;
/* Connect the flip-flop output to the buffer output and
delete the buffer. The XNF OUTFF can buffer the pin. */
connect(ff->pin_Q(0), buf->pin(0));
delete buf;
/* Finally, build up an XNF-LCA value that defines this
devices as an OUTFF and gives each pin an XNF name. */
char**names = new char*[ff->pin_count()];
for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1)
names[idx] = "";
if (ff->attribute("Clock:LPM_Polarity") == "INVERT")
names[ff->pin_Clock().get_pin()] = "~C";
else
names[ff->pin_Clock().get_pin()] = "C";
names[ff->pin_Data(0).get_pin()] = "D";
names[ff->pin_Q(0).get_pin()] = "Q";
string lname = string("OUTFF:") + names[0];
for (unsigned idx = 1 ; idx < ff->pin_count() ; idx += 1)
lname = lname + "," + names[idx];
delete[]names;
ff->attribute("XNF-LCA", lname);
}
static void make_ibuf(Design*des, NetNet*net)
@@ -178,7 +238,7 @@ static void make_ibuf(Design*des, NetNet*net)
// of the netlist, to create a ring without a signal. Detect
// this case and create a new signal.
if (count_signals(buf->pin(0)) == 0) {
NetNet*tmp = new NetNet(des->local_symbol("$"), NetNet::WIRE);
NetNet*tmp = new NetNet(0, des->local_symbol("$"), NetNet::WIRE);
connect(buf->pin(0), tmp->pin(0));
des->add_signal(tmp);
}
@@ -186,6 +246,7 @@ static void make_ibuf(Design*des, NetNet*net)
void xnfio_f::signal(Design*des, NetNet*net)
{
NetNode*buf;
if (! is_a_pad(net))
return;
@@ -198,9 +259,13 @@ void xnfio_f::signal(Design*des, NetNet*net)
make_ibuf(des, net);
break;
case 'o':
case 'O':
make_obuf(des, net);
break;
case 'O': {
NetLogic*buf = make_obuf(des, net);
if (buf == 0) break;
absorb_OFF(des, buf);
break;
}
// FIXME: Only IPAD and OPAD supported. Need to
// add support for IOPAD.
default:
@@ -217,6 +282,20 @@ void xnfio(Design*des)
/*
* $Log: xnfio.cc,v $
* Revision 1.9 1999/11/27 19:07:58 steve
* Support the creation of scopes.
*
* Revision 1.8 1999/11/19 05:02:15 steve
* Handle inverted clock into OUTFF.
*
* Revision 1.7 1999/11/19 03:02:25 steve
* Detect flip-flops connected to opads and turn
* them into OUTFF devices. Inprove support for
* the XNF-LCA attribute in the process.
*
* Revision 1.6 1999/11/18 02:58:37 steve
* Handle (with a warning) unconnected opads.
*
* Revision 1.5 1999/11/02 04:55:01 steve
* repair the sense of T from bufif01
*