mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-23 22:36:54 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f949f96df1 | ||
|
|
1d215998b2 | ||
|
|
492d76e71d | ||
|
|
1cc68f745a | ||
|
|
4d8c0c79d6 | ||
|
|
a7f48c86e2 | ||
|
|
35e84f15d4 | ||
|
|
d513cf8f60 | ||
|
|
efdc1769e6 | ||
|
|
e1c697a746 | ||
|
|
393c9ab108 | ||
|
|
efa5222c66 | ||
|
|
f068196272 | ||
|
|
8317d8707e | ||
|
|
ed9aeec591 | ||
|
|
0c1c826410 | ||
|
|
c63a3acf93 | ||
|
|
b37fcf3593 | ||
|
|
6e486e9bcf | ||
|
|
076cecb6cd | ||
|
|
42006ec5f1 | ||
|
|
db7044850a | ||
|
|
5ee7cfb854 | ||
|
|
93f05306e7 | ||
|
|
8e21f0f363 | ||
|
|
b2f7f533f7 | ||
|
|
2271fc9894 | ||
|
|
a64a33e65a | ||
|
|
3a415fb04c | ||
|
|
0c7722ce7e | ||
|
|
86a283b9bc | ||
|
|
0fb4ba7907 | ||
|
|
f274c9cade | ||
|
|
4882f04945 | ||
|
|
a8a2b3e8f3 | ||
|
|
900949ab56 | ||
|
|
9f30615a91 | ||
|
|
a964e0479b | ||
|
|
6d7ac5d67b | ||
|
|
470b0d3d34 | ||
|
|
bb38653654 | ||
|
|
fb678877d7 | ||
|
|
64cc38f0eb | ||
|
|
1a21d2fe9d | ||
|
|
095995f09c | ||
|
|
851daff66f | ||
|
|
1b7261a393 | ||
|
|
1c41f8ebd2 | ||
|
|
59b1b4c7b9 | ||
|
|
0955058fbe | ||
|
|
12b9071f49 | ||
|
|
357461b034 | ||
|
|
4a0e7d56bd | ||
|
|
da4a7ea80a | ||
|
|
fcfa9d004a | ||
|
|
349f9ae302 | ||
|
|
3a5e55b229 | ||
|
|
1f44822510 | ||
|
|
6df3febada | ||
|
|
5fde1b3e05 | ||
|
|
fbf104bf4d | ||
|
|
dab04c221d | ||
|
|
251eb4f38f | ||
|
|
424e6a750c | ||
|
|
4594ac1c2c | ||
|
|
d904aceb2c | ||
|
|
a890724b40 | ||
|
|
31bdb87c8f | ||
|
|
b04148b754 | ||
|
|
f36c511c2f | ||
|
|
39bc45ce67 | ||
|
|
3d78b558bc | ||
|
|
54d38ac057 | ||
|
|
7a211b9136 | ||
|
|
6847dac5c2 | ||
|
|
a3e9a7417d | ||
|
|
25d6912217 | ||
|
|
1c238f1948 | ||
|
|
287d21f300 | ||
|
|
a6c6ac2191 | ||
|
|
d6fbc30cd5 | ||
|
|
9d82d19d07 | ||
|
|
006a2cce83 | ||
|
|
8f68a07476 | ||
|
|
555d447180 | ||
|
|
41a1c6bb02 | ||
|
|
6fb7120158 | ||
|
|
9f7eb4a935 | ||
|
|
5ee83fce70 | ||
|
|
e69345b9fe | ||
|
|
1c11c864d5 | ||
|
|
58d05dfca2 | ||
|
|
7d71abaa05 | ||
|
|
6b3b6f3384 | ||
|
|
0fe25f68f9 | ||
|
|
3017636c05 | ||
|
|
23acca48ff | ||
|
|
648e4c68e4 | ||
|
|
9eae940ebd | ||
|
|
0175a4fce0 | ||
|
|
aba4a877db | ||
|
|
031d91f813 | ||
|
|
f1fdce78be | ||
|
|
b119613a8a | ||
|
|
567badc7af | ||
|
|
b62f094874 | ||
|
|
28c0691b5f | ||
|
|
2d0e11283d | ||
|
|
f1825c54a7 | ||
|
|
cf1abfe38c |
@@ -6,6 +6,7 @@ ivl
|
||||
dep
|
||||
configure
|
||||
Makefile
|
||||
verilog
|
||||
config.status
|
||||
config.log
|
||||
config.cache
|
||||
|
||||
+32
-6
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.11 1999/08/07 20:05:51 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.20 1999/09/29 01:50:35 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -33,6 +33,7 @@ VPATH = $(srcdir)
|
||||
|
||||
bindir = $(exec_prefix)/bin
|
||||
libdir = $(exec_prefix)/lib
|
||||
mandir = @mandir@
|
||||
includedir = $(prefix)/include
|
||||
|
||||
CC = @CC@
|
||||
@@ -45,27 +46,40 @@ CPPFLAGS = @CPPFLAGS@ @DEFS@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: ivl
|
||||
all: ivl verilog
|
||||
cd vpi ; make all
|
||||
cd vvm ; make all
|
||||
cd ivlpp ; make all
|
||||
|
||||
clean:
|
||||
rm *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc
|
||||
cd vpi ; make clean
|
||||
cd vvm ; make clean
|
||||
cd ivlpp ; make clean
|
||||
|
||||
TT = t-null.o t-verilog.o t-vvm.o t-xnf.o
|
||||
FF = nobufz.o propinit.o sigfold.o xnfio.o xnfsyn.o
|
||||
|
||||
O = main.o cprop.o design_dump.o elaborate.o emit.o eval.o functor.o \
|
||||
lexor.o mangle.o netlist.o parse.o parse_misc.o pform.o pform_dump.o \
|
||||
verinum.o verireal.o target.o targets.o Module.o PExpr.o PGate.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 \
|
||||
verinum.o verireal.o target.o targets.o Module.o PDelays.o PExpr.o PGate.o \
|
||||
PTask.o PFunction.o PWire.o Statement.o \
|
||||
$(FF) $(TT)
|
||||
|
||||
Makefile: Makefile.in config.status
|
||||
./config.status
|
||||
|
||||
# Make the actual verilog program from the script template. This
|
||||
# simply invloves editing the substitution strings in the script into
|
||||
# the configured copy.
|
||||
tmp1 = bindir
|
||||
tmp2 = libdir
|
||||
verilog: $(srcdir)/verilog.sh
|
||||
sed -e 's;@$(tmp1)@;@bindir@;' -e 's;@$(tmp2)@;@libdir@;' < $< > $@
|
||||
|
||||
ivl: $O
|
||||
$(CXX) $(CXXFLAGS) -o ivl $O
|
||||
|
||||
@@ -86,18 +100,30 @@ parse.h parse.cc: parse.y
|
||||
lexor.cc: lexor.lex
|
||||
flex -PVL -s -olexor.cc lexor.lex
|
||||
|
||||
install: all installdirs $(bindir)/ivl
|
||||
install: all installdirs $(bindir)/verilog $(bindir)/ivl $(mandir)/man1/verilog.1
|
||||
cd vpi ; make install
|
||||
cd vvm ; make install
|
||||
cd ivlpp ; make install
|
||||
|
||||
$(bindir)/verilog: ./verilog
|
||||
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
|
||||
|
||||
$(bindir)/ivl: ivl
|
||||
$(INSTALL_PROGRAM) ./ivl $(bindir)/ivl
|
||||
|
||||
$(mandir)/man1/verilog.1: $(srcdir)/verilog.1
|
||||
$(INSTALL_DATA) $(srcdir)/verilog.1 $(mandir)/man1/verilog.1
|
||||
|
||||
installdirs: mkinstalldirs
|
||||
$(srcdir)/mkinstalldirs $(includedir) $(bindir)
|
||||
|
||||
uninstall:
|
||||
rm -f $(bindir)/ivl
|
||||
rm -f $(bindir)/verilog
|
||||
rm -f $(mandir)/man1/verilog.1
|
||||
cd vpi ; make uninstall
|
||||
cd vvm ; make uninstall
|
||||
cd ivlpp ; make uninstall
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Module.cc,v 1.6 1999/08/04 02:13:02 steve Exp $"
|
||||
#ident "$Id: Module.cc,v 1.7 1999/09/17 02:06:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Module.h"
|
||||
@@ -30,6 +30,8 @@ Module::Module(const string&name, const svector<Module::port_t*>*pp)
|
||||
ports_ = *pp;
|
||||
for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) {
|
||||
port_t*cur = ports_[idx];
|
||||
if (cur == 0)
|
||||
continue;
|
||||
for (unsigned jdx = 0 ; jdx < cur->wires.count() ; jdx += 1)
|
||||
add_wire(cur->wires[jdx]);
|
||||
}
|
||||
@@ -99,6 +101,9 @@ PWire* Module::get_wire(const string&name)
|
||||
|
||||
/*
|
||||
* $Log: Module.cc,v $
|
||||
* Revision 1.7 1999/09/17 02:06:25 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
* Revision 1.6 1999/08/04 02:13:02 steve
|
||||
* Elaborate module ports that are concatenations of
|
||||
* module signals.
|
||||
|
||||
@@ -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.8 1999/08/04 02:13:02 steve Exp $"
|
||||
#ident "$Id: Module.h,v 1.9 1999/08/23 16:48:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <list>
|
||||
@@ -64,6 +64,14 @@ class Module {
|
||||
into this map. */
|
||||
map<string,PExpr*>parameters;
|
||||
|
||||
/* Parameters may be overridden at instantiation time;
|
||||
the overrides do not contain explicit parameter names,
|
||||
but rather refer to parameters in the order they
|
||||
appear in the instantiated module. Therefore a
|
||||
list of names in module-order is needed to pass from
|
||||
a parameter-index to its name. */
|
||||
list<string> param_names;
|
||||
|
||||
const string&get_name() const { return name_; }
|
||||
|
||||
void add_gate(PGate*gate);
|
||||
@@ -85,7 +93,7 @@ class Module {
|
||||
const list<PProcess*>& get_behaviors() const { return behaviors_; }
|
||||
|
||||
void dump(ostream&out) const;
|
||||
bool elaborate(Design*, const string&path) const;
|
||||
bool elaborate(Design*, const string&path, svector<PExpr*>*overrides_) const;
|
||||
|
||||
private:
|
||||
const string name_;
|
||||
@@ -105,6 +113,10 @@ class Module {
|
||||
|
||||
/*
|
||||
* $Log: Module.h,v $
|
||||
* Revision 1.9 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.8 1999/08/04 02:13:02 steve
|
||||
* Elaborate module ports that are concatenations of
|
||||
* module signals.
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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: PDelays.cc,v 1.1 1999/09/04 19:11:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PDelays.h"
|
||||
# include "PExpr.h"
|
||||
# include "verinum.h"
|
||||
|
||||
PDelays::PDelays()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
|
||||
delay_[idx] = 0;
|
||||
}
|
||||
|
||||
PDelays::~PDelays()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
|
||||
delete delay_[idx];
|
||||
}
|
||||
|
||||
void PDelays::set_delay(PExpr*del)
|
||||
{
|
||||
assert(del);
|
||||
assert(delay_[0] == 0);
|
||||
delay_[0] = del;
|
||||
}
|
||||
|
||||
|
||||
void PDelays::set_delays(const svector<PExpr*>*del)
|
||||
{
|
||||
assert(del);
|
||||
assert(del->count() <= 3);
|
||||
for (unsigned idx = 0 ; idx < del->count() ; idx += 1)
|
||||
delay_[idx] = (*del)[idx];
|
||||
}
|
||||
|
||||
void PDelays::eval_delays(Design*des, const string&path,
|
||||
unsigned long&rise_time,
|
||||
unsigned long&fall_time,
|
||||
unsigned long&decay_time) const
|
||||
{
|
||||
verinum*dv;
|
||||
|
||||
if (delay_[0]) {
|
||||
dv = delay_[0]->eval_const(des, path);
|
||||
assert(dv);
|
||||
rise_time = dv->as_ulong();
|
||||
delete dv;
|
||||
|
||||
if (delay_[1]) {
|
||||
dv = delay_[1]->eval_const(des, path);
|
||||
assert(dv);
|
||||
fall_time = dv->as_ulong();
|
||||
delete dv;
|
||||
|
||||
if (delay_[2]) {
|
||||
dv = delay_[2]->eval_const(des, path);
|
||||
assert(dv);
|
||||
decay_time = dv->as_ulong();
|
||||
delete dv;
|
||||
} else {
|
||||
if (rise_time < fall_time)
|
||||
decay_time = rise_time;
|
||||
else
|
||||
decay_time = fall_time;
|
||||
}
|
||||
} else {
|
||||
assert(delay_[2] == 0);
|
||||
fall_time = rise_time;
|
||||
decay_time = rise_time;
|
||||
}
|
||||
} else {
|
||||
rise_time = 0;
|
||||
fall_time = 0;
|
||||
decay_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: PDelays.cc,v $
|
||||
* Revision 1.1 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef __PDelays_H
|
||||
#define __PDelays_H
|
||||
/*
|
||||
* 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: PDelays.h,v 1.1 1999/09/04 19:11:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "svector.h"
|
||||
# include <string>
|
||||
class Design;
|
||||
class PExpr;
|
||||
class ostream;
|
||||
|
||||
/*
|
||||
* Various PForm objects can carry delays. These delays include rise,
|
||||
* fall and decay times. This class arranges to carry the triplet.
|
||||
*/
|
||||
class PDelays {
|
||||
|
||||
public:
|
||||
PDelays();
|
||||
~PDelays();
|
||||
|
||||
void set_delay(PExpr*);
|
||||
void set_delays(const svector<PExpr*>*del);
|
||||
|
||||
void eval_delays(Design*des, const string&path,
|
||||
unsigned long&rise_time,
|
||||
unsigned long&fall_time,
|
||||
unsigned long&decay_time) const;
|
||||
|
||||
void dump_delays(ostream&out) const;
|
||||
|
||||
private:
|
||||
PExpr* delay_[3];
|
||||
|
||||
private: // not implemented
|
||||
PDelays(const PDelays&);
|
||||
PDelays& operator= (const PDelays&);
|
||||
};
|
||||
|
||||
ostream& operator << (ostream&o, const PDelays&);
|
||||
|
||||
/*
|
||||
* $Log: PDelays.h,v $
|
||||
* Revision 1.1 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PExpr.cc,v 1.7 1999/07/22 02:05:20 steve Exp $"
|
||||
#ident "$Id: PExpr.cc,v 1.10 1999/09/25 02:57:29 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
@@ -38,14 +38,40 @@ bool PExpr::is_constant(Module*) const
|
||||
return false;
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_net(Design*des, const string&path,
|
||||
unsigned long,
|
||||
unsigned long,
|
||||
unsigned long) const
|
||||
{
|
||||
cerr << "Don't know how to elaborate `" << *this
|
||||
<< "' as gates." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_lnet(Design*des, const string&path) const
|
||||
{
|
||||
cerr << get_line() << ": expression not valid in assign l-value: "
|
||||
<< *this << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool PEBinary::is_constant(Module*mod) const
|
||||
{
|
||||
return left_->is_constant(mod) && right_->is_constant(mod);
|
||||
}
|
||||
|
||||
PECallFunction::PECallFunction(const string &n, const svector<PExpr *> &parms)
|
||||
: name_(n), parms_(parms)
|
||||
{
|
||||
}
|
||||
|
||||
PECallFunction::~PECallFunction()
|
||||
{
|
||||
}
|
||||
|
||||
bool PEConcat::is_constant(Module *mod) const
|
||||
{
|
||||
bool constant = repeat_->is_constant(mod);
|
||||
bool constant = repeat_? repeat_->is_constant(mod) : true;
|
||||
for (unsigned i = 0; constant && i < parms_.count(); ++i) {
|
||||
constant = constant && parms_[i]->is_constant(mod);
|
||||
}
|
||||
@@ -102,6 +128,15 @@ bool PETernary::is_constant(Module*) const
|
||||
|
||||
/*
|
||||
* $Log: PExpr.cc,v $
|
||||
* Revision 1.10 1999/09/25 02:57:29 steve
|
||||
* Parse system function calls.
|
||||
*
|
||||
* Revision 1.9 1999/09/16 04:18:15 steve
|
||||
* elaborate concatenation repeats.
|
||||
*
|
||||
* Revision 1.8 1999/09/15 04:17:52 steve
|
||||
* separate assign lval elaboration for error checking.
|
||||
*
|
||||
* Revision 1.7 1999/07/22 02:05:20 steve
|
||||
* is_constant method for PEConcat.
|
||||
*
|
||||
|
||||
@@ -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.17 1999/08/01 21:18:55 steve Exp $"
|
||||
#ident "$Id: PExpr.h,v 1.20 1999/09/25 02:57:29 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
@@ -47,11 +47,20 @@ class PExpr : public LineInfo {
|
||||
virtual ~PExpr();
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
// Procedural elaboration of the expression.
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
// This method elaborate the expression as gates, for use in a
|
||||
// continuous assign or other wholy structural context.
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
unsigned long decay =0) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
// This method elaborates the expression as gates, but
|
||||
// restricted for use as l-values of continuous assignments.
|
||||
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
|
||||
|
||||
// This attempts to evaluate a constant expression, and return
|
||||
// a verinum as a result. If the expression cannot be
|
||||
@@ -80,6 +89,7 @@ class PEConcat : public PExpr {
|
||||
~PEConcat();
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
@@ -116,11 +126,18 @@ class PEIdent : public PExpr {
|
||||
: text_(s), msb_(0), lsb_(0), idx_(0) { }
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
// Identifiers are allowed (with restrictions) is assign l-values.
|
||||
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
|
||||
|
||||
// Structural r-values are OK.
|
||||
virtual NetNet* elaborate_net(Design*des, const string&path,
|
||||
unsigned long rise =0,
|
||||
unsigned long fall =0,
|
||||
unsigned long decay =0) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
virtual bool is_constant(Module*) const;
|
||||
verinum* eval_const(const Design*des, const string&path) const;
|
||||
|
||||
@@ -246,22 +263,35 @@ class PETernary : public PExpr {
|
||||
PExpr*fal_;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This class represents a parsed call to a function.
|
||||
*/
|
||||
class PECallFunction : public PExpr {
|
||||
public:
|
||||
explicit PECallFunction(const string &n, const svector<PExpr *> &parms)
|
||||
: name_(n), parms_(parms) {}
|
||||
~PECallFunction() {}
|
||||
public:
|
||||
explicit PECallFunction(const string &n, const svector<PExpr *> &parms);
|
||||
~PECallFunction();
|
||||
|
||||
virtual void dump(ostream &) const;
|
||||
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
string name_;
|
||||
svector<PExpr *> parms_;
|
||||
|
||||
NetESFunc* elaborate_sfunc_(Design*des, const string&path) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PExpr.h,v $
|
||||
* Revision 1.20 1999/09/25 02:57:29 steve
|
||||
* Parse system function calls.
|
||||
*
|
||||
* Revision 1.19 1999/09/15 04:17:52 steve
|
||||
* separate assign lval elaboration for error checking.
|
||||
*
|
||||
* Revision 1.18 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.17 1999/08/01 21:18:55 steve
|
||||
* elaborate rise/fall/decay for continuous assign.
|
||||
*
|
||||
|
||||
+36
-1
@@ -1,10 +1,45 @@
|
||||
/*
|
||||
* 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: PFunction.cc,v 1.2 1999/08/25 22:22:41 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "PTask.h"
|
||||
|
||||
PFunction::PFunction(svector<PWire*>*p, Statement*s)
|
||||
: ports_(p), statement_(s)
|
||||
: out_(0), ports_(p), statement_(s)
|
||||
{
|
||||
}
|
||||
|
||||
PFunction::~PFunction()
|
||||
{
|
||||
}
|
||||
|
||||
void PFunction::set_output(PWire*o)
|
||||
{
|
||||
assert(out_ == 0);
|
||||
out_ = o;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: PFunction.cc,v $
|
||||
* Revision 1.2 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PGate.cc,v 1.3 1999/08/01 21:18:55 steve Exp $"
|
||||
#ident "$Id: PGate.cc,v 1.5 1999/09/14 01:50:35 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PGate.h"
|
||||
@@ -30,14 +30,7 @@ PGate::PGate(const string&name,
|
||||
const svector<PExpr*>*del)
|
||||
: name_(name), pins_(pins)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
|
||||
delay_[idx] = 0;
|
||||
|
||||
if (del) {
|
||||
assert(del->count() <= 3);
|
||||
for (unsigned idx = 0 ; idx < del->count() ; idx += 1)
|
||||
delay_[idx] = (*del)[idx];
|
||||
}
|
||||
if (del) delay_.set_delays(del);
|
||||
}
|
||||
|
||||
PGate::PGate(const string&name,
|
||||
@@ -45,23 +38,16 @@ PGate::PGate(const string&name,
|
||||
PExpr*del)
|
||||
: name_(name), pins_(pins)
|
||||
{
|
||||
delay_[0] = del;
|
||||
delay_[1] = 0;
|
||||
delay_[2] = 0;
|
||||
if (del) delay_.set_delay(del);
|
||||
}
|
||||
|
||||
PGate::PGate(const string&name, svector<PExpr*>*pins)
|
||||
: name_(name), pins_(pins)
|
||||
{
|
||||
delay_[0] = 0;
|
||||
delay_[1] = 0;
|
||||
delay_[2] = 0;
|
||||
}
|
||||
|
||||
PGate::~PGate()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
|
||||
delete delay_[idx];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -77,41 +63,7 @@ void PGate::eval_delays(Design*des, const string&path,
|
||||
unsigned long&fall_time,
|
||||
unsigned long&decay_time) const
|
||||
{
|
||||
verinum*dv;
|
||||
|
||||
if (delay_[0]) {
|
||||
dv = delay_[0]->eval_const(des, path);
|
||||
assert(dv);
|
||||
rise_time = dv->as_ulong();
|
||||
delete dv;
|
||||
|
||||
if (delay_[1]) {
|
||||
dv = delay_[1]->eval_const(des, path);
|
||||
assert(dv);
|
||||
fall_time = dv->as_ulong();
|
||||
delete dv;
|
||||
|
||||
if (delay_[2]) {
|
||||
dv = delay_[2]->eval_const(des, path);
|
||||
assert(dv);
|
||||
decay_time = dv->as_ulong();
|
||||
delete dv;
|
||||
} else {
|
||||
if (rise_time < fall_time)
|
||||
decay_time = rise_time;
|
||||
else
|
||||
decay_time = fall_time;
|
||||
}
|
||||
} else {
|
||||
assert(delay_[2] == 0);
|
||||
fall_time = rise_time;
|
||||
decay_time = rise_time;
|
||||
}
|
||||
} else {
|
||||
rise_time = 0;
|
||||
fall_time = 0;
|
||||
decay_time = 0;
|
||||
}
|
||||
delay_.eval_delays(des, path, rise_time, fall_time, decay_time);
|
||||
}
|
||||
|
||||
PGAssign::PGAssign(svector<PExpr*>*pins)
|
||||
@@ -160,6 +112,12 @@ void PGBuiltin::set_range(PExpr*msb, PExpr*lsb)
|
||||
|
||||
/*
|
||||
* $Log: PGate.cc,v $
|
||||
* Revision 1.5 1999/09/14 01:50:35 steve
|
||||
* Handle gates without delays.
|
||||
*
|
||||
* Revision 1.4 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.3 1999/08/01 21:18:55 steve
|
||||
* elaborate rise/fall/decay for continuous assign.
|
||||
*
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PGate.h,v 1.8 1999/08/01 21:18:55 steve Exp $"
|
||||
#ident "$Id: PGate.h,v 1.10 1999/09/04 19:11:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "svector.h"
|
||||
# include "LineInfo.h"
|
||||
# include "PDelays.h"
|
||||
class PExpr;
|
||||
class PUdp;
|
||||
class Design;
|
||||
@@ -72,7 +73,7 @@ class PGate : public LineInfo {
|
||||
|
||||
private:
|
||||
const string name_;
|
||||
PExpr* delay_[3];
|
||||
PDelays delay_;
|
||||
svector<PExpr*>*pins_;
|
||||
|
||||
private: // not implemented
|
||||
@@ -150,8 +151,8 @@ class PGModule : public PGate {
|
||||
// If the binding of ports is by position, this constructor
|
||||
// builds everything all at once.
|
||||
explicit PGModule(const string&type, const string&name,
|
||||
svector<PExpr*>*pins)
|
||||
: PGate(name, pins), type_(type), pins_(0), npins_(0) { }
|
||||
svector<PExpr*>*overrides, svector<PExpr*>*pins)
|
||||
: PGate(name, pins), type_(type), overrides_(overrides), pins_(0), npins_(0) { }
|
||||
|
||||
// If the binding of ports is by name, this constructor takes
|
||||
// the bindings and stores them for later elaboration.
|
||||
@@ -160,8 +161,8 @@ class PGModule : public PGate {
|
||||
PExpr* parm;
|
||||
};
|
||||
explicit PGModule(const string&type, const string&name,
|
||||
bind_t*pins, unsigned npins)
|
||||
: PGate(name, 0), type_(type), pins_(pins), npins_(npins) { }
|
||||
svector<PExpr*>*overrides, bind_t*pins, unsigned npins)
|
||||
: PGate(name, 0), type_(type), overrides_(overrides), pins_(pins), npins_(npins) { }
|
||||
|
||||
|
||||
virtual void dump(ostream&out) const;
|
||||
@@ -169,6 +170,7 @@ class PGModule : public PGate {
|
||||
|
||||
private:
|
||||
string type_;
|
||||
svector<PExpr*>*overrides_;
|
||||
bind_t*pins_;
|
||||
unsigned npins_;
|
||||
|
||||
@@ -178,6 +180,13 @@ class PGModule : public PGate {
|
||||
|
||||
/*
|
||||
* $Log: PGate.h,v $
|
||||
* Revision 1.10 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.9 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.8 1999/08/01 21:18:55 steve
|
||||
* elaborate rise/fall/decay for continuous assign.
|
||||
*
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PTask.h,v 1.3 1999/07/31 19:14:47 steve Exp $"
|
||||
#ident "$Id: PTask.h,v 1.6 1999/09/30 21:28:34 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "LineInfo.h"
|
||||
@@ -38,7 +38,9 @@ class PTask : public LineInfo {
|
||||
explicit PTask(svector<PWire*>*p, Statement*s);
|
||||
~PTask();
|
||||
|
||||
virtual void elaborate(Design*des, const string&path) const;
|
||||
void elaborate_1(Design*des, const string&path) const;
|
||||
void elaborate_2(Design*des, const string&path) const;
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
|
||||
private:
|
||||
@@ -50,21 +52,45 @@ class PTask : public LineInfo {
|
||||
PTask& operator=(const PTask&);
|
||||
};
|
||||
|
||||
/*
|
||||
* The function is similar to a task (in this context) but there is a
|
||||
* single output port and a set of input ports. The output port is the
|
||||
* function return value.
|
||||
*/
|
||||
class PFunction : public LineInfo {
|
||||
public:
|
||||
explicit PFunction(svector<PWire *> *p, Statement *s);
|
||||
|
||||
public:
|
||||
explicit PFunction(svector<PWire *>*p, Statement *s);
|
||||
~PFunction();
|
||||
|
||||
//virtual void elaborate(Design *des, const string &path) const {}
|
||||
void set_output(PWire*);
|
||||
|
||||
/* Functions are elaborated in 2 passes. */
|
||||
void elaborate_1(Design *des, const string &path) const;
|
||||
void elaborate_2(Design *des, const string &path) const;
|
||||
|
||||
void dump(ostream&, unsigned) const;
|
||||
|
||||
private:
|
||||
private:
|
||||
PWire*out_;
|
||||
svector<PWire *> *ports_;
|
||||
Statement *statement_;
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: PTask.h,v $
|
||||
* Revision 1.6 1999/09/30 21:28:34 steve
|
||||
* Handle mutual reference of tasks by elaborating
|
||||
* task definitions in two passes, like functions.
|
||||
*
|
||||
* Revision 1.5 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.4 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.3 1999/07/31 19:14:47 steve
|
||||
* Add functions up to elaboration (Ed Carter)
|
||||
*
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: PWire.cc,v 1.1 1999/06/17 05:34:42 steve Exp $"
|
||||
#ident "$Id: PWire.cc,v 1.2 1999/09/10 05:02:09 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PWire.h"
|
||||
@@ -41,6 +41,10 @@ bool PWire::set_wire_type(NetNet::Type t)
|
||||
case NetNet::IMPLICIT:
|
||||
type_ = t;
|
||||
return true;
|
||||
case NetNet::IMPLICIT_REG:
|
||||
if (t == NetNet::REG) { type_ = t; return true; }
|
||||
if (t == NetNet::INTEGER) {type_ = t; return true; }
|
||||
return false;
|
||||
case NetNet::REG:
|
||||
if (t == NetNet::REG) return true;
|
||||
if (t == NetNet::INTEGER) {type_ = t; return true; }
|
||||
@@ -96,6 +100,9 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
|
||||
|
||||
/*
|
||||
* $Log: PWire.cc,v $
|
||||
* Revision 1.2 1999/09/10 05:02:09 steve
|
||||
* Handle integers at task parameters.
|
||||
*
|
||||
* Revision 1.1 1999/06/17 05:34:42 steve
|
||||
* Clean up interface of the PWire class,
|
||||
* Properly match wire ranges.
|
||||
|
||||
+89
-64
@@ -1,12 +1,14 @@
|
||||
THE ICARUS VERILOG COMPILATION SYSTEM
|
||||
July 7, 1999
|
||||
September 18, 1999
|
||||
|
||||
|
||||
1.0 What is ICARUS Verilog(IVL)?
|
||||
|
||||
Icarus Verilog is intended to compile ALL of the Verilog HDL as described
|
||||
in the IEEE-1364 standard. Of course, it's not quite there yet. It does
|
||||
currently handle a mix of structural and behavioral constructs.
|
||||
currently handle a mix of structural and behavioral constructs. For a
|
||||
view of the current state of Icarus Verilog, see its home page at
|
||||
<http://www.icarus.com/pub/verilog>.
|
||||
|
||||
IVL is not aimed at being a simulator in the traditional sense, but a
|
||||
compiler that generates code employed by back-end tools. These back-
|
||||
@@ -19,7 +21,7 @@ and an XNF (Xilinx Netlist Format) generator. See "vvm.txt" and
|
||||
This tool includes a parser which reads in Verilog (plus extensions)
|
||||
and generates an internal netlist. The netlist is passed to various
|
||||
processing steps that transform the design to more optimal/practical
|
||||
forms, then passed to a code generator for final output. The
|
||||
forms, then is passed to a code generator for final output. The
|
||||
processing steps and the code generator are selected by command line
|
||||
switches.
|
||||
|
||||
@@ -27,15 +29,16 @@ switches.
|
||||
|
||||
There is a separate program, ivlpp, that does the preprocessing. This
|
||||
program implements the `include and `define directives producing
|
||||
output that is equivalent but without the directives. See
|
||||
ivlpp/ivlpp.txt for details.
|
||||
output that is equivalent but without the directives. The output is a
|
||||
single file with line number directives, so that the actual compiler
|
||||
only sees a single input file. See ivlpp/ivlpp.txt for details.
|
||||
|
||||
2.2 Parse
|
||||
|
||||
The verilog compiler starts by parsing the verilog source file. The
|
||||
output of the parse in a list of Module objects in PFORM. The pform
|
||||
(see pform.h) is mostly a direct reflection of the compilation
|
||||
unit. There may be dangling references, and it is not yet clear which
|
||||
step. There may be dangling references, and it is not yet clear which
|
||||
module is the root.
|
||||
|
||||
One can see a human readable version of the final PFORM by using the
|
||||
@@ -47,7 +50,8 @@ PFORM into the file named <path>.
|
||||
This phase takes the pform and generates a netlist. The driver selects
|
||||
(by user request or lucky guess) the root module to elaborate,
|
||||
resolves references and expands the instantiations to form the design
|
||||
netlist. (See netlist.txt.)
|
||||
netlist. (See netlist.txt.) Final semantic checks are performed during
|
||||
elaboration, and some simple optimizations are performed.
|
||||
|
||||
The elaborate() function performs the elaboration.
|
||||
|
||||
@@ -84,23 +88,27 @@ command line.
|
||||
|
||||
3.0 Building/Installing IVL
|
||||
|
||||
Unpack the tar-ball and cd into the verilog-######### directory.
|
||||
Unpack the tar-ball and cd into the verilog-######### directory, and
|
||||
compile the source with the commands:
|
||||
|
||||
./configure
|
||||
make
|
||||
cd vvm
|
||||
make
|
||||
./configure
|
||||
make
|
||||
|
||||
Now install the files in an appropriate place. (The makefiles by
|
||||
default install in /usr/local unless you specify a different prefix
|
||||
with the --prefix=<path> flag to the configure command.) Do this as
|
||||
root.
|
||||
|
||||
make install
|
||||
cd vvm
|
||||
make install
|
||||
make install
|
||||
|
||||
4.0 Running IVL
|
||||
4.0 Running Verilog
|
||||
|
||||
The preferred way to invoke the compiler with the verilog(1)
|
||||
command. This program invokes the preprocessor (ivlpp) and the
|
||||
compiler (ivl) with the proper command line options to get the job
|
||||
done in a friendly way. See the verilog(1) man page for usage details.
|
||||
|
||||
4.1 Running IVL Directly
|
||||
|
||||
The ivl command is the compiler driver, that invokes the parser,
|
||||
optimization functions and the code generator.
|
||||
@@ -208,78 +216,89 @@ endmodule
|
||||
|
||||
--------------------------------------------------------------
|
||||
|
||||
Insure that "ivl" is on your search path, and the library
|
||||
libvvm.a is available.
|
||||
Insure that "verilog" is on your search path, and the vpi library
|
||||
is available.
|
||||
|
||||
For csh -
|
||||
|
||||
setenv PATH /usr/local/bin:$PATH
|
||||
setenv LD_LIBRARY_PATH /usr/local/lib:$LD_LIBRARY_PATH
|
||||
setenv PATH /usr/local/bin:$PATH
|
||||
setenv VPI_MODULE_PATH /usr/local/lib/ivl
|
||||
|
||||
ivl -t vvm -o hello.cc hello.vl
|
||||
g++ hello.cc -o hello -lvvm
|
||||
verilog hello.vl
|
||||
|
||||
(The above presumes that /usr/local/include and /usr/local/lib are
|
||||
part of the compiler search path, which is usually the case for egcs.)
|
||||
part of the compiler search path, which is usually the case for gcc.)
|
||||
|
||||
To run the program
|
||||
|
||||
./hello
|
||||
./hello
|
||||
|
||||
|
||||
5.0 Unsupported Constructs
|
||||
|
||||
IVL is in development - as such it still only supports a (growing) subset
|
||||
of verilog. Below is a description of some of the currently unsupported
|
||||
verilog features.
|
||||
|
||||
- The "?" operator. Example: count = val ? 1 : 0;
|
||||
|
||||
- Ranges within parameter definitions:
|
||||
Example: parameter [15:0] seed = 16'ha3;
|
||||
|
||||
[Note: IEEE Std: 1364-1995 does not allow the syntax.]
|
||||
|
||||
- The "&&" operator:
|
||||
Example: if (a && 0) do = 1;
|
||||
|
||||
- The "===" operator: Example: if( a === b) do = 1;
|
||||
|
||||
- The ">=" operator: Example: if ( a >= 0) do = 1;
|
||||
|
||||
- The ">" operator: Example: if ( a > 0) do = 1;
|
||||
|
||||
- The "<=" operator: Example: if ( a <= 0) do = 1;
|
||||
|
||||
- The "<<" shift operator: Example: a = 8'b0000_0010 << 1;
|
||||
verilog features. This list is not exhaustive, and does not account
|
||||
for errors in the compiler. See the Icarus Verilog web page for the
|
||||
current state of support for Verilog.
|
||||
|
||||
- Min/Typ/Max expressions: Example: a = (1 : 6 : 14);
|
||||
|
||||
- Expansion of a string into a larger variable:
|
||||
Example: reg [0:15] b; b = "b";
|
||||
- Memories work, but only in procedural code.
|
||||
|
||||
- Function declarations/calls.
|
||||
|
||||
- Non-scalar memories, i.e. other than registers.
|
||||
Example: reg [1:0] b [2:0];
|
||||
|
||||
- Delay list. Example: sample #(9,99) sample1(a,b);
|
||||
|
||||
- Bit ranges within IF. Example: if (a[2:3]) do = 1;
|
||||
|
||||
- Assignment timing delay: Example: a = #1 0; #1 a = #2 ~a;
|
||||
|
||||
- Bit Ranges within $write, $display.
|
||||
reg [1:0] b [2:0], bar;
|
||||
wire [1:0] foo;
|
||||
always foo = b[i]; // sorry
|
||||
always @(i) bar = b[i]; // OK
|
||||
|
||||
- `timescale directive
|
||||
|
||||
- Specify blocks
|
||||
- force/release/assign/deassign procedural assignments not
|
||||
supported.
|
||||
|
||||
- Named port parameters.
|
||||
Example: module foo(.x(r[0])) ; reg r[7:0]; endmodule
|
||||
- block disable not supported, i.e.:
|
||||
|
||||
begin : foo
|
||||
[...]
|
||||
disable foo; // sorry
|
||||
[...]
|
||||
end
|
||||
|
||||
- fork/join is not supported in vvm runtime
|
||||
|
||||
- structural arithmetic operators are in general not
|
||||
supported. Procedural expressions are OK.
|
||||
|
||||
assign foo = a + b; // sorry
|
||||
always @(a or b) foo = a + b; // OK
|
||||
|
||||
- Functions in structural contexts are not supported.
|
||||
|
||||
assign foo = user_function(a,b); // sorry
|
||||
always @(a or b) foo = user_function(a,b); // OK
|
||||
|
||||
- multiplicative operators (*, /, %) are not supported.
|
||||
|
||||
assign foo = a * b; // sorry
|
||||
always @(a or b) foo = a * b; // sorry
|
||||
|
||||
- event data type is not supported.
|
||||
|
||||
- real data type not supported.
|
||||
|
||||
- system functions are not supported. (User defined functions are
|
||||
supported, and system tasks are supported.)
|
||||
|
||||
assign foo = $some_function(a,b); // sorry
|
||||
always @(a or b) foo = $some_function(a,b); // sorry
|
||||
|
||||
- non-constant delay expressions, i.e.:
|
||||
|
||||
reg [7:0] del;
|
||||
always #(reg) $display($time,,"del = %d", del); // sorry
|
||||
|
||||
Specify blocks are parsed but ignored in general.
|
||||
|
||||
Note that binding to a port by name does work from the outside.
|
||||
i.e. ``foo foogate(.x(n[0]))'' is OK.
|
||||
|
||||
6.0 CREDITS
|
||||
|
||||
@@ -288,9 +307,15 @@ Williams. The proper notices are in the head of each file. However,
|
||||
I have received aid in the form of fixes, Verilog guidance, and
|
||||
especially testing from many people, including (in alphabetical order):
|
||||
|
||||
Eric Aardoom <[email protected]>
|
||||
Ed Carter <[email protected]>
|
||||
Larry Doolittle <[email protected]>
|
||||
Guy Hutchison <[email protected]>
|
||||
Ales Hvezda <[email protected]>
|
||||
James Lee <[email protected]>
|
||||
Peter Monta <[email protected]>
|
||||
Daniel H. Nelsen <[email protected]>
|
||||
Stefan Petersen <[email protected]>
|
||||
Jason Schonberg <[email protected]>
|
||||
Stuart Sutherland <[email protected]>
|
||||
Stephen Tell <[email protected]>
|
||||
|
||||
+39
-7
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Statement.cc,v 1.12 1999/07/12 00:59:36 steve Exp $"
|
||||
#ident "$Id: Statement.cc,v 1.16 1999/09/29 18:36:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "Statement.h"
|
||||
@@ -27,20 +27,30 @@ Statement::~Statement()
|
||||
{
|
||||
}
|
||||
|
||||
PAssign_::PAssign_(PExpr*lval, PExpr*ex)
|
||||
: event_(0), lval_(lval), rval_(ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssign_::PAssign_(PExpr*lval, PExpr*de, PExpr*ex)
|
||||
: lval_(lval), delay_(de), rval_(ex)
|
||||
: event_(0), lval_(lval), rval_(ex)
|
||||
{
|
||||
if (de) delay_.set_delay(de);
|
||||
}
|
||||
|
||||
PAssign_::PAssign_(PExpr*lval, PEventStatement*ev, PExpr*ex)
|
||||
: event_(ev), lval_(lval), rval_(ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssign_::~PAssign_()
|
||||
{
|
||||
delete lval_;
|
||||
delete delay_;
|
||||
delete rval_;
|
||||
}
|
||||
|
||||
PAssign::PAssign(PExpr*lval, PExpr*ex)
|
||||
: PAssign_(lval, 0, ex)
|
||||
: PAssign_(lval, ex)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -49,12 +59,22 @@ PAssign::PAssign(PExpr*lval, PExpr*d, PExpr*ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssign::PAssign(PExpr*lval, PEventStatement*d, PExpr*ex)
|
||||
: PAssign_(lval, d, ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssign::~PAssign()
|
||||
{
|
||||
}
|
||||
|
||||
PAssignNB::PAssignNB(PExpr*lval, PExpr*ex)
|
||||
: PAssign_(lval, 0, ex)
|
||||
: PAssign_(lval, ex)
|
||||
{
|
||||
}
|
||||
|
||||
PAssignNB::PAssignNB(PExpr*lval, PExpr*d, PExpr*ex)
|
||||
: PAssign_(lval, d, ex)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -88,8 +108,8 @@ PCallTask::PCallTask(const string&n, const svector<PExpr*>&p)
|
||||
{
|
||||
}
|
||||
|
||||
PCase::PCase(PExpr*ex, svector<PCase::Item*>*l)
|
||||
: expr_(ex), items_(l)
|
||||
PCase::PCase(NetCase::TYPE t, PExpr*ex, svector<PCase::Item*>*l)
|
||||
: type_(t), expr_(ex), items_(l)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -143,6 +163,18 @@ PWhile::~PWhile()
|
||||
|
||||
/*
|
||||
* $Log: Statement.cc,v $
|
||||
* Revision 1.16 1999/09/29 18:36:02 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.15 1999/09/22 02:00:48 steve
|
||||
* assignment with blocking event delay.
|
||||
*
|
||||
* Revision 1.14 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.13 1999/09/02 01:59:27 steve
|
||||
* Parse non-blocking assignment delays.
|
||||
*
|
||||
* Revision 1.12 1999/07/12 00:59:36 steve
|
||||
* procedural blocking assignment delays.
|
||||
*
|
||||
|
||||
+33
-4
@@ -19,15 +19,17 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: Statement.h,v 1.15 1999/07/12 00:59:36 steve Exp $"
|
||||
#ident "$Id: Statement.h,v 1.20 1999/09/29 18:36:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
# include "svector.h"
|
||||
# include "PDelays.h"
|
||||
# include "PExpr.h"
|
||||
# include "LineInfo.h"
|
||||
class PExpr;
|
||||
class Statement;
|
||||
class PEventStatement;
|
||||
|
||||
/*
|
||||
* The PProcess is the root of a behavioral process. Each process gets
|
||||
@@ -77,11 +79,12 @@ class Statement : public LineInfo {
|
||||
*/
|
||||
class PAssign_ : public Statement {
|
||||
public:
|
||||
explicit PAssign_(PExpr*lval, PExpr*ex);
|
||||
explicit PAssign_(PExpr*lval, PExpr*de, PExpr*ex);
|
||||
explicit PAssign_(PExpr*lval, PEventStatement*de, PExpr*ex);
|
||||
virtual ~PAssign_() =0;
|
||||
|
||||
const PExpr* lval() const { return lval_; }
|
||||
const PExpr* delay() const { return delay_; }
|
||||
const PExpr* rval() const { return rval_; }
|
||||
|
||||
protected:
|
||||
@@ -89,9 +92,11 @@ class PAssign_ : public Statement {
|
||||
unsigned&lsb, unsigned&msb,
|
||||
NetExpr*&mux) const;
|
||||
|
||||
PDelays delay_;
|
||||
PEventStatement*event_;
|
||||
|
||||
private:
|
||||
PExpr* lval_;
|
||||
PExpr* delay_;
|
||||
PExpr* rval_;
|
||||
};
|
||||
|
||||
@@ -100,6 +105,7 @@ class PAssign : public PAssign_ {
|
||||
public:
|
||||
explicit PAssign(PExpr*lval, PExpr*ex);
|
||||
explicit PAssign(PExpr*lval, PExpr*de, PExpr*ex);
|
||||
explicit PAssign(PExpr*lval, PEventStatement*de, PExpr*ex);
|
||||
~PAssign();
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
@@ -114,12 +120,15 @@ class PAssignNB : public PAssign_ {
|
||||
|
||||
public:
|
||||
explicit PAssignNB(PExpr*lval, PExpr*ex);
|
||||
explicit PAssignNB(PExpr*lval, PExpr*de, PExpr*ex);
|
||||
~PAssignNB();
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
private:
|
||||
NetProc*assign_to_memory_(class NetMemory*, PExpr*,
|
||||
Design*des, const string&path) const;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -191,13 +200,14 @@ class PCase : public Statement {
|
||||
Statement*stat;
|
||||
};
|
||||
|
||||
PCase(PExpr*ex, svector<Item*>*);
|
||||
PCase(NetCase::TYPE, PExpr*ex, svector<Item*>*);
|
||||
~PCase();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
NetCase::TYPE type_;
|
||||
PExpr*expr_;
|
||||
|
||||
svector<Item*>*items_;
|
||||
@@ -256,6 +266,10 @@ class PEventStatement : public Statement {
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, const string&path) const;
|
||||
|
||||
// This method is used to elaborate, but attach a previously
|
||||
// elaborated statement to the event.
|
||||
NetProc* elaborate_st(Design*des, const string&path, NetProc*st) const;
|
||||
|
||||
private:
|
||||
svector<PEEvent*>expr_;
|
||||
Statement*statement_;
|
||||
@@ -333,6 +347,21 @@ class PWhile : public Statement {
|
||||
|
||||
/*
|
||||
* $Log: Statement.h,v $
|
||||
* Revision 1.20 1999/09/29 18:36:02 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.19 1999/09/22 02:00:48 steve
|
||||
* assignment with blocking event delay.
|
||||
*
|
||||
* Revision 1.18 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.17 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.16 1999/09/02 01:59:27 steve
|
||||
* Parse non-blocking assignment delays.
|
||||
*
|
||||
* Revision 1.15 1999/07/12 00:59:36 steve
|
||||
* procedural blocking assignment delays.
|
||||
*
|
||||
|
||||
+1
-1
@@ -6,4 +6,4 @@ AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_OUTPUT(Makefile ivlpp/Makefile vvm/Makefile)
|
||||
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
|
||||
|
||||
+171
-31
@@ -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.34 1999/08/01 16:34:50 steve Exp $"
|
||||
#ident "$Id: design_dump.cc,v 1.48 1999/10/07 05:25:33 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -121,26 +121,35 @@ void NetObj::dump_obj_attr(ostream&o, unsigned ind) const
|
||||
}
|
||||
}
|
||||
|
||||
void NetAddSub::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Adder (NetAddSub): " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetAssign::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Procedural assign: " << *rval_ << endl;
|
||||
o << setw(ind) << "" << "Procedural assign (NetAssign): " << name();
|
||||
if (bmux())
|
||||
o << "[" << *bmux() << "]";
|
||||
o << " = " << *rval() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetAssignNB::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
if (bmux_)
|
||||
o << setw(ind) << "" << "Procedural NB assign: " << name()
|
||||
<< "[" << *bmux_ << "] <= " << *rval_ << endl;
|
||||
if (bmux())
|
||||
o << setw(ind) << "" << "Procedural NB assign (NetAssignNB): "
|
||||
<< name() << "[" << *bmux() << "] <= " << *rval() << endl;
|
||||
else
|
||||
o << setw(ind) << "" << "Procedural NB assign: " << name()
|
||||
<< " <= " << *rval_ << endl;
|
||||
o << setw(ind) << "" << "Procedural NB assign (NetAssignNB): "
|
||||
<< name() << " <= " << *rval() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
void NetBUFZ::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "BUFZ: " << name() << endl;
|
||||
o << setw(ind) << "" << "NetBUFZ: " << name() << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
|
||||
@@ -327,28 +336,35 @@ void NetAssign::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
|
||||
const NetNet*sig;
|
||||
unsigned msb, lsb;
|
||||
find_lval_range(sig, msb, lsb);
|
||||
o << sig->name() << "[" << msb;
|
||||
if (pin_count() > 1)
|
||||
o << ":" << lsb;
|
||||
o << "] = ";
|
||||
|
||||
rval_->dump(o);
|
||||
o << ";" << endl;
|
||||
if (bmux()) {
|
||||
o << name() << "[" << *bmux() << "] = ";
|
||||
if (rise_time())
|
||||
o << "#" << rise_time() << " ";
|
||||
o << *rval() << ";" << endl;
|
||||
|
||||
} else {
|
||||
o << name() << " = ";
|
||||
if (rise_time())
|
||||
o << "#" << rise_time() << " ";
|
||||
o << *rval() << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void NetAssignNB::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
|
||||
if (bmux_) {
|
||||
o << name() << "[" << *bmux_ << "] <= " << *rval_ << ";" <<
|
||||
endl;
|
||||
if (bmux()) {
|
||||
o << name() << "[" << *bmux() << "] <= ";
|
||||
if (rise_time())
|
||||
o << "#" << rise_time() << " ";
|
||||
o << *rval() << ";" << endl;
|
||||
|
||||
} else {
|
||||
o << name() << " <= " << *rval_ << ";" << endl;
|
||||
o << name() << " <= ";
|
||||
if (rise_time())
|
||||
o << "#" << rise_time() << " ";
|
||||
o << *rval() << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,10 +373,22 @@ void NetAssignMem::dump(ostream&o, unsigned ind) const
|
||||
o << setw(ind) << "";
|
||||
o << "/* " << get_line() << " */" << endl;
|
||||
o << setw(ind) << "";
|
||||
o << mem_->name() << "[";
|
||||
index_->dump(o);
|
||||
o << memory()->name() << "[";
|
||||
index()->dump(o);
|
||||
o << "] = ";
|
||||
rval_->dump(o);
|
||||
rval()->dump(o);
|
||||
o << ";" << endl;
|
||||
}
|
||||
|
||||
void NetAssignMemNB::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
o << "/* " << get_line() << " */" << endl;
|
||||
o << setw(ind) << "";
|
||||
o << memory()->name() << "[";
|
||||
index()->dump(o);
|
||||
o << "] <= ";
|
||||
rval()->dump(o);
|
||||
o << ";" << endl;
|
||||
}
|
||||
|
||||
@@ -382,7 +410,14 @@ void NetBlock::dump(ostream&o, unsigned ind) const
|
||||
|
||||
void NetCase::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "case (" << *expr_ << ")" << endl;
|
||||
switch (type_) {
|
||||
case EQ:
|
||||
o << setw(ind) << "" << "case (" << *expr_ << ")" << endl;
|
||||
case EQX:
|
||||
o << setw(ind) << "" << "casex (" << *expr_ << ")" << endl;
|
||||
case EQZ:
|
||||
o << setw(ind) << "" << "casez (" << *expr_ << ")" << endl;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) {
|
||||
o << setw(ind+2) << "";
|
||||
@@ -423,6 +458,15 @@ void NetForever::dump(ostream&o, unsigned ind) const
|
||||
statement_->dump(o, ind+2);
|
||||
}
|
||||
|
||||
void NetFuncDef::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "function " << name_ << endl;
|
||||
if (statement_)
|
||||
statement_->dump(o, ind+2);
|
||||
else
|
||||
o << setw(ind+2) << "" << "// NO STATEMENT" << endl;
|
||||
}
|
||||
|
||||
void NetPDelay::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "#" << delay_;
|
||||
@@ -558,9 +602,15 @@ void NetEBinary::dump(ostream&o) const
|
||||
case 'o':
|
||||
o << "||";
|
||||
break;
|
||||
case 'O':
|
||||
o << "~|";
|
||||
break;
|
||||
case 'r':
|
||||
o << ">>";
|
||||
break;
|
||||
case 'X':
|
||||
o << "~^";
|
||||
break;
|
||||
}
|
||||
o << "(";
|
||||
right_->dump(o);
|
||||
@@ -569,9 +619,20 @@ void NetEBinary::dump(ostream&o) const
|
||||
|
||||
void NetEConcat::dump(ostream&o) const
|
||||
{
|
||||
o << "{" << *parms_[0];
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1)
|
||||
o << ", " << *parms_[idx];
|
||||
if (repeat_ != 1)
|
||||
o << repeat_;
|
||||
|
||||
if (parms_[0])
|
||||
o << "{" << *parms_[0];
|
||||
else
|
||||
o << "{";
|
||||
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
|
||||
if (parms_[idx])
|
||||
o << ", " << *parms_[idx];
|
||||
else
|
||||
o << ", ";
|
||||
}
|
||||
o << "}";
|
||||
}
|
||||
|
||||
@@ -608,9 +669,15 @@ void NetEMemory::dump(ostream&o) const
|
||||
o << "]";
|
||||
}
|
||||
|
||||
void NetEParam::dump(ostream&o) const
|
||||
{
|
||||
o << "<" << path_ << "." << name_ << ">";
|
||||
}
|
||||
|
||||
void NetESignal::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "Expression Node: " << name() << endl;
|
||||
o << setw(ind) << "" << "Expression Node (NetESignal): " <<
|
||||
name() << endl;
|
||||
|
||||
dump_node_pins(o, ind+4);
|
||||
}
|
||||
@@ -621,9 +688,29 @@ void NetETernary::dump(ostream&o) const
|
||||
false_val_ << ")";
|
||||
}
|
||||
|
||||
void NetEUFunc::dump(ostream&o) const
|
||||
{
|
||||
o << name() << "(";
|
||||
assert(parms_.count() > 0);
|
||||
parms_[0]->dump(o);
|
||||
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
|
||||
o << ", ";
|
||||
parms_[idx]->dump(o);
|
||||
}
|
||||
o << ")";
|
||||
}
|
||||
|
||||
void NetEUnary::dump(ostream&o) const
|
||||
{
|
||||
o << op_ << "(";
|
||||
switch (op_) {
|
||||
case 'N':
|
||||
o << "~|";
|
||||
break;
|
||||
default:
|
||||
o << op_;
|
||||
break;
|
||||
}
|
||||
o << "(";
|
||||
expr_->dump(o);
|
||||
o << ")";
|
||||
}
|
||||
@@ -660,6 +747,15 @@ void Design::dump(ostream&o) const
|
||||
}
|
||||
}
|
||||
|
||||
o << "ELABORATED FUNCTION DEFINITIONS:" << endl;
|
||||
{
|
||||
map<string,NetFuncDef*>::const_iterator pp;
|
||||
for (pp = funcs_.begin()
|
||||
; pp != funcs_.end() ; pp ++) {
|
||||
(*pp).second->dump(o, 0);
|
||||
}
|
||||
}
|
||||
|
||||
o << "ELABORATED TASK DEFINITIONS:" << endl;
|
||||
{
|
||||
map<string,NetTaskDef*>::const_iterator pp;
|
||||
@@ -690,6 +786,50 @@ void Design::dump(ostream&o) const
|
||||
|
||||
/*
|
||||
* $Log: design_dump.cc,v $
|
||||
* Revision 1.48 1999/10/07 05:25:33 steve
|
||||
* Add non-const bit select in l-value of assignment.
|
||||
*
|
||||
* Revision 1.47 1999/10/06 05:06:16 steve
|
||||
* Move the rvalue into NetAssign_ common code.
|
||||
*
|
||||
* Revision 1.46 1999/10/05 06:19:46 steve
|
||||
* Add support for reduction NOR.
|
||||
*
|
||||
* Revision 1.45 1999/09/30 02:43:01 steve
|
||||
* Elaborate ~^ and ~| operators.
|
||||
*
|
||||
* Revision 1.44 1999/09/29 18:36:03 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.43 1999/09/21 00:13:40 steve
|
||||
* Support parameters that reference other paramters.
|
||||
*
|
||||
* Revision 1.42 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
* Revision 1.41 1999/09/19 01:06:36 steve
|
||||
* dump the repeat count, if applicable.
|
||||
*
|
||||
* Revision 1.40 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.39 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.38 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* 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/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.34 1999/08/01 16:34:50 steve
|
||||
* Parse and elaborate rise/fall/decay times
|
||||
* for gates, and handle the rules for partial
|
||||
|
||||
+340
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* 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: elab_expr.cc,v 1.6 1999/09/30 02:43:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
|
||||
# include "pform.h"
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* Elaborate binary expressions. This involves elaborating the left
|
||||
* and right sides, and creating one of a variety of different NetExpr
|
||||
* types.
|
||||
*/
|
||||
NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
bool flag;
|
||||
NetExpr*lp = left_->elaborate_expr(des, path);
|
||||
NetExpr*rp = right_->elaborate_expr(des, path);
|
||||
if ((lp == 0) || (rp == 0)) {
|
||||
delete lp;
|
||||
delete rp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If either expression can be evaluated ahead of time, then
|
||||
do so. This can prove helpful later. */
|
||||
{ NetExpr*tmp;
|
||||
tmp = lp->eval_tree();
|
||||
if (tmp) {
|
||||
delete lp;
|
||||
lp = tmp;
|
||||
}
|
||||
tmp = rp->eval_tree();
|
||||
if (tmp) {
|
||||
delete rp;
|
||||
rp = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
NetEBinary*tmp;
|
||||
switch (op_) {
|
||||
default:
|
||||
tmp = new NetEBinary(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
case 'o':
|
||||
tmp = new NetEBLogic(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 'r':
|
||||
tmp = new NetEBShift(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case '^':
|
||||
case '&':
|
||||
case '|':
|
||||
case 'O':
|
||||
case 'X':
|
||||
tmp = new NetEBBits(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
tmp = new NetEBAdd(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
break;
|
||||
|
||||
case 'e': /* == */
|
||||
case 'E': /* === */
|
||||
case 'n': /* != */
|
||||
case 'N': /* !== */
|
||||
case 'L': /* <= */
|
||||
case 'G': /* >= */
|
||||
case '<':
|
||||
case '>':
|
||||
tmp = new NetEBComp(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
flag = tmp->set_width(1);
|
||||
if (flag == false) {
|
||||
cerr << get_line() << ": internal error: "
|
||||
"expression bit width of comparison != 1." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetESFunc* PECallFunction::elaborate_sfunc_(Design*des, const string&path) const
|
||||
{
|
||||
cerr << get_line() << ": sorry: system functions not supported."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
if (name_[0] == '$')
|
||||
return elaborate_sfunc_(des, path);
|
||||
|
||||
string myname = path+"."+name_;
|
||||
NetFuncDef*def = des->find_function(path, name_);
|
||||
if (def == 0) {
|
||||
cerr << get_line() << ": error: No function " << name_ <<
|
||||
" in this context (" << path << ")." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(def);
|
||||
svector<NetExpr*> parms (parms_.count());
|
||||
|
||||
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
|
||||
NetExpr*tmp = parms_[idx]->elaborate_expr(des, myname);
|
||||
parms[idx] = tmp;
|
||||
}
|
||||
|
||||
/* Look for the return value signal for the called function in
|
||||
the context of the function definition, not my context. */
|
||||
NetNet*res = des->find_signal(def->name(), name_);
|
||||
if (res == 0) {
|
||||
cerr << get_line() << ": internal error: Unable to locate "
|
||||
"function return value for " << name_ << " in " <<
|
||||
def->name() << "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(res);
|
||||
NetESignal*eres = new NetESignal(res);
|
||||
assert(eres);
|
||||
des->add_node(eres);
|
||||
NetEUFunc*func = new NetEUFunc(def, eres, parms);
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
// System identifiers show up in the netlist as identifiers.
|
||||
if (text_[0] == '$')
|
||||
return new NetEIdent(text_, 64);
|
||||
|
||||
string name = path+"."+text_;
|
||||
|
||||
// If the identifier name is a parameter name, then return
|
||||
// a reference to the parameter expression.
|
||||
if (const NetExpr*ex = des->find_parameter(path, text_)) {
|
||||
NetExpr*tmp;
|
||||
if (dynamic_cast<const NetExpr*>(ex))
|
||||
tmp = ex->dup_expr();
|
||||
else
|
||||
tmp = new NetEParam(des, path, text_);
|
||||
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// If the identifier names a signal (a register or wire)
|
||||
// then create a NetESignal node to handle it.
|
||||
if (NetNet*net = des->find_signal(path, text_)) {
|
||||
|
||||
// If this is a part select of a signal, then make a new
|
||||
// temporary signal that is connected to just the
|
||||
// selected bits.
|
||||
if (lsb_) {
|
||||
assert(msb_);
|
||||
verinum*lsn = lsb_->eval_const(des, path);
|
||||
verinum*msn = msb_->eval_const(des, path);
|
||||
if ((lsn == 0) || (msn == 0)) {
|
||||
cerr << get_line() << ": error: "
|
||||
"Part select expresions must be "
|
||||
"constant expressions." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(lsn);
|
||||
assert(msn);
|
||||
unsigned long lsv = lsn->as_ulong();
|
||||
unsigned long msv = msn->as_ulong();
|
||||
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
|
||||
assert(wid <= net->pin_count());
|
||||
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);
|
||||
|
||||
// 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));
|
||||
|
||||
des->add_node(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// If the bit select is constant, then treat it similar
|
||||
// to the part select, so that I save the effort of
|
||||
// making a mux part in the netlist.
|
||||
verinum*msn;
|
||||
if (msb_ && (msn = msb_->eval_const(des, path))) {
|
||||
assert(idx_ == 0);
|
||||
unsigned long msv = msn->as_ulong();
|
||||
|
||||
string tname = des->local_symbol(path);
|
||||
NetESignal*tmp = new NetESignal(tname, 1);
|
||||
tmp->set_line(*this);
|
||||
connect(tmp->pin(0), net->pin(msv));
|
||||
|
||||
des->add_node(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetESignal*node = new NetESignal(net);
|
||||
des->add_node(node);
|
||||
assert(idx_ == 0);
|
||||
|
||||
// Non-constant bit select? punt and make a subsignal
|
||||
// device to mux the bit in the net.
|
||||
if (msb_) {
|
||||
NetExpr*ex = msb_->elaborate_expr(des, path);
|
||||
NetESubSignal*ss = new NetESubSignal(node, ex);
|
||||
ss->set_line(*this);
|
||||
return ss;
|
||||
}
|
||||
|
||||
// All else fails, return the signal itself as the
|
||||
// expression.
|
||||
assert(msb_ == 0);
|
||||
return node;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
assert(msb_ != 0);
|
||||
assert(lsb_ == 0);
|
||||
assert(idx_ == 0);
|
||||
NetExpr*i = msb_->elaborate_expr(des, path);
|
||||
if (i == 0) {
|
||||
cerr << get_line() << ": error: Unable to exaborate "
|
||||
"index expression `" << *msb_ << "'" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEMemory*node = new NetEMemory(mem, i);
|
||||
node->set_line(*this);
|
||||
return node;
|
||||
}
|
||||
|
||||
// I cannot interpret this identifier. Error message.
|
||||
cerr << get_line() << ": error: Unable to bind wire/reg/memory "
|
||||
"`" << path << "." << text_ << "'" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate the Ternary operator. I know that the expressions were
|
||||
* parsed so I can presume that they exist, and call elaboration
|
||||
* methods. If any elaboration fails, then give up and return 0.
|
||||
*/
|
||||
NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const
|
||||
{
|
||||
assert(expr_);
|
||||
assert(tru_);
|
||||
assert(fal_);
|
||||
|
||||
NetExpr*con = expr_->elaborate_expr(des, path);
|
||||
if (con == 0)
|
||||
return 0;
|
||||
|
||||
NetExpr*tru = tru_->elaborate_expr(des, path);
|
||||
if (tru == 0) {
|
||||
delete con;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*fal = fal_->elaborate_expr(des, path);
|
||||
if (fal == 0) {
|
||||
delete con;
|
||||
delete tru;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetETernary*res = new NetETernary(con, tru, fal);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: elab_expr.cc,v $
|
||||
* Revision 1.6 1999/09/30 02:43:02 steve
|
||||
* Elaborate ~^ and ~| operators.
|
||||
*
|
||||
* Revision 1.5 1999/09/30 00:48:49 steve
|
||||
* Cope with errors during ternary operator elaboration.
|
||||
*
|
||||
* Revision 1.4 1999/09/29 22:57:10 steve
|
||||
* Move code to elab_expr.cc
|
||||
*
|
||||
* Revision 1.3 1999/09/25 02:57:30 steve
|
||||
* Parse system function calls.
|
||||
*
|
||||
* Revision 1.2 1999/09/21 00:13:40 steve
|
||||
* Support parameters that reference other paramters.
|
||||
*
|
||||
* Revision 1.1 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
*/
|
||||
|
||||
+1019
-379
File diff suppressed because it is too large
Load Diff
@@ -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.18 1999/07/17 19:50:59 steve Exp $"
|
||||
#ident "$Id: emit.cc,v 1.23 1999/09/22 16:57:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -45,6 +45,11 @@ void NetUDP::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->udp(o, this);
|
||||
}
|
||||
|
||||
void NetAddSub::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->lpm_add_sub(o, this);
|
||||
}
|
||||
|
||||
void NetAssign::emit_node(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->net_assign(o, this);
|
||||
@@ -70,54 +75,68 @@ void NetBUFZ::emit_node(ostream&o, struct target_t*tgt) const
|
||||
tgt->bufz(o, this);
|
||||
}
|
||||
|
||||
void NetProcTop::emit(ostream&o, struct target_t*tgt) const
|
||||
bool NetProcTop::emit(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->process(o, this);
|
||||
return tgt->process(o, this);
|
||||
}
|
||||
|
||||
void NetProc::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetProc::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
cerr << "EMIT: Proc type? " << typeid(*this).name() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_assign(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_assign_nb(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_assign_mem(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetAssignMemNB::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_block(o, this);
|
||||
tgt->proc_assign_mem_nb(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetCase::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_block(o, this);
|
||||
}
|
||||
|
||||
bool NetCase::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_case(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_condit(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetForever::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetForever::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_forever(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_delay(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
@@ -125,9 +144,10 @@ void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
if (statement_) statement_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_event(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
@@ -135,24 +155,28 @@ void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
if (statement_) statement_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_repeat(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_stask(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_utask(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetWhile::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
bool NetWhile::emit_proc(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_while(o, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetBlock::emit_recurse(ostream&o, struct target_t*tgt) const
|
||||
@@ -196,8 +220,9 @@ void NetWhile::emit_proc_recurse(ostream&o, struct target_t*tgt) const
|
||||
proc_->emit_proc(o, tgt);
|
||||
}
|
||||
|
||||
void Design::emit(ostream&o, struct target_t*tgt) const
|
||||
bool Design::emit(ostream&o, struct target_t*tgt) const
|
||||
{
|
||||
bool rc = true;
|
||||
tgt->start_design(o, this);
|
||||
|
||||
// emit signals
|
||||
@@ -229,6 +254,14 @@ void Design::emit(ostream&o, struct target_t*tgt) const
|
||||
}
|
||||
|
||||
|
||||
// emit function definitions
|
||||
{
|
||||
map<string,NetFuncDef*>::const_iterator ta;
|
||||
for (ta = funcs_.begin() ; ta != funcs_.end() ; ta ++) {
|
||||
tgt->func_def(o, (*ta).second);
|
||||
}
|
||||
}
|
||||
|
||||
// emit task definitions
|
||||
{
|
||||
map<string,NetTaskDef*>::const_iterator ta;
|
||||
@@ -239,9 +272,10 @@ void Design::emit(ostream&o, struct target_t*tgt) const
|
||||
|
||||
// emit the processes
|
||||
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
|
||||
idx->emit(o, tgt);
|
||||
rc = rc && idx->emit(o, tgt);
|
||||
|
||||
tgt->end_design(o, this);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void NetEBinary::expr_scan(struct expr_scan_t*tgt) const
|
||||
@@ -269,6 +303,17 @@ void NetEMemory::expr_scan(struct expr_scan_t*tgt) const
|
||||
tgt->expr_memory(this);
|
||||
}
|
||||
|
||||
void NetEParam::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
cerr << get_line() << ":internal error: unexpected NetEParam."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
void NetEUFunc::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_ufunc(this);
|
||||
}
|
||||
|
||||
void NetESignal::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_signal(this);
|
||||
@@ -294,20 +339,34 @@ void NetEUnary::expr_scan(struct expr_scan_t*tgt) const
|
||||
tgt->expr_unary(this);
|
||||
}
|
||||
|
||||
void emit(ostream&o, const Design*des, const char*type)
|
||||
bool emit(ostream&o, const Design*des, const char*type)
|
||||
{
|
||||
for (unsigned idx = 0 ; target_table[idx] ; idx += 1) {
|
||||
const struct target*tgt = target_table[idx];
|
||||
if (tgt->name == type) {
|
||||
des->emit(o, tgt->meth);
|
||||
return;
|
||||
}
|
||||
if (tgt->name == type)
|
||||
return des->emit(o, tgt->meth);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: emit.cc,v $
|
||||
* Revision 1.23 1999/09/22 16:57:23 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.22 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
* Revision 1.21 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.20 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* Revision 1.19 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.18 1999/07/17 19:50:59 steve
|
||||
* netlist support for ternary operator.
|
||||
*
|
||||
|
||||
@@ -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.5 1999/08/06 04:05:28 steve Exp $"
|
||||
#ident "$Id: eval.cc,v 1.8 1999/09/20 02:21:10 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "PExpr.h"
|
||||
@@ -56,11 +56,24 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate an identifier as a constant expression. This is only
|
||||
* possible if the identifier is that of a parameter.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (expr == 0)
|
||||
return 0;
|
||||
|
||||
if (dynamic_cast<const NetEParam*>(expr)) {
|
||||
cerr << get_line() << ": sorry: I cannot evaluate ``" <<
|
||||
text_ << "'' in this context." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const NetEConst*eval = dynamic_cast<const NetEConst*>(expr);
|
||||
assert(eval);
|
||||
return new verinum(eval->value());
|
||||
@@ -79,6 +92,15 @@ verinum* PETernary::eval_const(const Design*, const string&) const
|
||||
|
||||
/*
|
||||
* $Log: eval.cc,v $
|
||||
* Revision 1.8 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
* Revision 1.7 1999/09/18 01:52:48 steve
|
||||
* Remove spurious message.
|
||||
*
|
||||
* Revision 1.6 1999/09/16 04:18:15 steve
|
||||
* elaborate concatenation repeats.
|
||||
*
|
||||
* Revision 1.5 1999/08/06 04:05:28 steve
|
||||
* Handle scope of parameters.
|
||||
*
|
||||
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* 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: eval_tree.cc,v 1.4 1999/09/23 03:56:57 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
NetExpr* NetExpr::eval_tree()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
|
||||
* Some of the derived classes can be evaluated by the compiler, this
|
||||
* method provides the common aid of evaluating the parameter
|
||||
* expressions.
|
||||
*/
|
||||
void NetEBinary::eval_sub_tree_()
|
||||
{
|
||||
NetExpr*tmp = left_->eval_tree();
|
||||
if (tmp) {
|
||||
delete left_;
|
||||
left_ = tmp;
|
||||
}
|
||||
tmp = right_->eval_tree();
|
||||
if (tmp){
|
||||
delete right_;
|
||||
right_ = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NetExpr* NetEBComp::eval_eqeq_()
|
||||
{
|
||||
NetEConst*l = dynamic_cast<NetEConst*>(left_);
|
||||
if (l == 0) return 0;
|
||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||
if (r == 0) return 0;
|
||||
|
||||
const verinum&lv = l->value();
|
||||
const verinum&rv = r->value();
|
||||
|
||||
if (lv.len() < rv.len())
|
||||
return 0;
|
||||
|
||||
verinum result(verinum::V1, 1);
|
||||
for (unsigned idx = 0 ; idx < lv.len(); idx += 1) {
|
||||
if (lv[idx] != rv[idx])
|
||||
result = verinum::V0;
|
||||
}
|
||||
|
||||
return new NetEConst(result);
|
||||
}
|
||||
|
||||
|
||||
NetExpr* NetEBComp::eval_leeq_()
|
||||
{
|
||||
NetEConst*r = dynamic_cast<NetEConst*>(right_);
|
||||
if (r == 0) return 0;
|
||||
|
||||
verinum rv = r->value();
|
||||
|
||||
/* Detect the case where the right side is greater that or
|
||||
equal to the largest value the left side can possibly
|
||||
have. */
|
||||
unsigned long lv = (1 << left_->expr_width()) - 1;
|
||||
if (lv <= rv.as_ulong()) {
|
||||
verinum result(verinum::V1, 1);
|
||||
return new NetEConst(result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
NetExpr* NetEBComp::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
|
||||
switch (op_) {
|
||||
case 'e':
|
||||
return eval_eqeq_();
|
||||
|
||||
case 'L':
|
||||
return eval_leeq_();
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NetExpr* NetEBLogic::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate the shift operator if possible. For this to work, both
|
||||
* operands must be constant.
|
||||
*/
|
||||
NetExpr* NetEBShift::eval_tree()
|
||||
{
|
||||
eval_sub_tree_();
|
||||
NetEConst*re = dynamic_cast<NetEConst*>(right_);
|
||||
if (re == 0)
|
||||
return 0;
|
||||
|
||||
NetEConst*le = dynamic_cast<NetEConst*>(left_);
|
||||
if (le == 0)
|
||||
return 0;
|
||||
|
||||
NetEConst*res;
|
||||
|
||||
verinum rv = re->value();
|
||||
verinum lv = le->value();
|
||||
if (rv.is_defined()) {
|
||||
|
||||
unsigned wid = expr_width();
|
||||
unsigned shift = rv.as_ulong();
|
||||
|
||||
verinum nv (verinum::V0, wid);
|
||||
|
||||
if (op() == 'r')
|
||||
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
|
||||
nv.set(idx, lv[idx+shift]);
|
||||
|
||||
else
|
||||
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
|
||||
nv.set(idx+shift, lv[idx]);
|
||||
|
||||
res = new NetEConst(nv);
|
||||
|
||||
} else {
|
||||
verinum nv (verinum::Vx, expr_width());
|
||||
res = new NetEConst(nv);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEConcat::eval_tree()
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
|
||||
|
||||
// Parameter not here? This is an error, but presumably
|
||||
// already caught and we are here just to catch more.
|
||||
if (parms_[idx] == 0)
|
||||
continue;
|
||||
|
||||
// If this parameter is already a constant, all is well
|
||||
// so go on.
|
||||
if (dynamic_cast<NetEConst*>(parms_[idx]))
|
||||
continue;
|
||||
|
||||
// Finally, try to evaluate the parameter expression
|
||||
// that is here. If I succeed, reset the parameter to
|
||||
// the evaluated value.
|
||||
assert(parms_[idx]);
|
||||
NetExpr*expr = parms_[idx]->eval_tree();
|
||||
if (expr) {
|
||||
delete parms_[idx];
|
||||
parms_[idx] = expr;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned gap = expr_width() / repeat_;
|
||||
verinum val (verinum::Vx, repeat_ * gap);
|
||||
|
||||
|
||||
// build up the result from least significant to most.
|
||||
|
||||
unsigned cur = 0;
|
||||
for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) {
|
||||
NetEConst*expr = dynamic_cast<NetEConst*>(parms_[idx-1]);
|
||||
if (expr == 0)
|
||||
return 0;
|
||||
|
||||
verinum tmp = expr->value();
|
||||
for (unsigned bit = 0 ; bit < tmp.len() ; bit += 1, cur += 1)
|
||||
for (unsigned rep = 0 ; rep < repeat_ ; rep += 1)
|
||||
val.set(rep*gap+cur, tmp[bit]);
|
||||
}
|
||||
|
||||
NetEConst*res = new NetEConst(val);
|
||||
res->set_width(val.len());
|
||||
return res;
|
||||
}
|
||||
|
||||
NetExpr* NetEParam::eval_tree()
|
||||
{
|
||||
if (des_ == 0)
|
||||
return 0;
|
||||
|
||||
const NetExpr*expr = des_->find_parameter(path_, name_);
|
||||
assert(expr);
|
||||
|
||||
NetExpr*nexpr = expr->dup_expr();
|
||||
assert(nexpr);
|
||||
|
||||
// If the parameter that I refer to is already evaluated, then
|
||||
// return the constant value.
|
||||
if (dynamic_cast<NetEConst*>(nexpr))
|
||||
return nexpr;
|
||||
|
||||
// Try to evaluate the expression. If I cannot, then the
|
||||
// expression is not a constant expression and I fail here.
|
||||
NetExpr*res = nexpr->eval_tree();
|
||||
if (res == 0) {
|
||||
delete nexpr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The result can be saved as the value of the parameter for
|
||||
// future reference, and return a copy to the caller.
|
||||
des_->set_parameter(path_+"."+name_, res);
|
||||
return res->dup_expr();
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: eval_tree.cc,v $
|
||||
* Revision 1.4 1999/09/23 03:56:57 steve
|
||||
* Support shift operators.
|
||||
*
|
||||
* Revision 1.3 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.2 1999/09/21 00:13:40 steve
|
||||
* Support parameters that reference other paramters.
|
||||
*
|
||||
* Revision 1.1 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
*/
|
||||
|
||||
+5
-2
@@ -19,12 +19,12 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: globals.h,v 1.1 1999/07/03 20:03:47 steve Exp $"
|
||||
#ident "$Id: globals.h,v 1.2 1999/09/05 22:33:18 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
|
||||
extern void reset_lexor(FILE*out, const char*ipath);
|
||||
extern void reset_lexor(FILE*out, char*paths[]);
|
||||
extern void define_macro(const char*name, const char*value);
|
||||
|
||||
/* These variables contain the include directories to be searched when
|
||||
@@ -40,6 +40,9 @@ extern int yyparse();
|
||||
|
||||
/*
|
||||
* $Log: globals.h,v $
|
||||
* Revision 1.2 1999/09/05 22:33:18 steve
|
||||
* Take multiple source files on the command line.
|
||||
*
|
||||
* Revision 1.1 1999/07/03 20:03:47 steve
|
||||
* Add include path and line directives.
|
||||
*
|
||||
|
||||
+63
-10
@@ -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.11 1999/07/25 00:03:13 steve Exp $"
|
||||
#ident "$Id: lexor.lex,v 1.13 1999/09/16 00:49:05 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <stdio.h>
|
||||
@@ -60,6 +60,7 @@ struct include_stack_t {
|
||||
struct include_stack_t*next;
|
||||
};
|
||||
|
||||
static struct include_stack_t*file_queue = 0;
|
||||
static struct include_stack_t*istack = 0;
|
||||
static struct include_stack_t*standby = 0;
|
||||
|
||||
@@ -114,7 +115,7 @@ W [ \t\b\f]+
|
||||
that follows it. when the directive ends, the do_include function
|
||||
performs the include operation. */
|
||||
|
||||
^`include { BEGIN(PPINCLUDE); }
|
||||
^{W}?`include { BEGIN(PPINCLUDE); }
|
||||
|
||||
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
|
||||
|
||||
@@ -128,7 +129,7 @@ W [ \t\b\f]+
|
||||
directive and the name, go into PPDEFINE mode and prepare to
|
||||
collect the defined value. */
|
||||
|
||||
^`define{W}[a-zA-Z][a-zA-Z0-9_]*{W}? { BEGIN(PPDEFINE); def_start(); }
|
||||
`define{W}[a-zA-Z][a-zA-Z0-9_]*{W}? { BEGIN(PPDEFINE); def_start(); }
|
||||
|
||||
<PPDEFINE>.*\n {
|
||||
do_define();
|
||||
@@ -137,7 +138,7 @@ W [ \t\b\f]+
|
||||
BEGIN(0);
|
||||
}
|
||||
|
||||
^`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
|
||||
`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
|
||||
|
||||
|
||||
/* Detect conditional compilation directives, and parse them. If I
|
||||
@@ -469,12 +470,18 @@ static void do_include()
|
||||
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
|
||||
}
|
||||
|
||||
/*
|
||||
* The lexical analyzer calls this function when the current file
|
||||
* ends. Here I pop the include stack and resume the previous file. If
|
||||
* there is no previous file, then the main input is ended.
|
||||
*/
|
||||
static int yywrap()
|
||||
{
|
||||
int line_mask_flag = 0;
|
||||
struct include_stack_t*isp = istack;
|
||||
istack = isp->next;
|
||||
|
||||
/* Delete the current input buffers, and free the cell. */
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
if (isp->file) {
|
||||
fclose(isp->file);
|
||||
@@ -492,13 +499,41 @@ static int yywrap()
|
||||
}
|
||||
free(isp);
|
||||
|
||||
if (istack == 0)
|
||||
return 1;
|
||||
/* If I am out if include stack, the main input is
|
||||
done. Look for another file to process in the input
|
||||
queue. If none are there, give up. Otherwise, open the file
|
||||
and continue parsing. */
|
||||
if (istack == 0) {
|
||||
if (file_queue == 0)
|
||||
return 1;
|
||||
|
||||
istack = file_queue;
|
||||
file_queue = file_queue->next;
|
||||
istack->next = 0;
|
||||
istack->lineno = 0;
|
||||
|
||||
istack->file = fopen(istack->path, "r");
|
||||
if (istack->file == 0) {
|
||||
perror(istack->path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (line_direct_flag)
|
||||
fprintf(yyout, "#line \"%s\" 0\n", istack->path);
|
||||
|
||||
yyrestart(isp->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Otherwise, resume the input buffer that is the new stack
|
||||
top. If I need to print a line directive, do so. */
|
||||
|
||||
yy_switch_to_buffer(istack->yybs);
|
||||
|
||||
if (line_direct_flag && istack->path && !line_mask_flag)
|
||||
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -507,14 +542,16 @@ static int yywrap()
|
||||
* opened, and the lexor is initialized. The include stack is cleared
|
||||
* and ready to go.
|
||||
*/
|
||||
void reset_lexor(FILE*out, const char*path)
|
||||
void reset_lexor(FILE*out, char*paths[])
|
||||
{
|
||||
unsigned idx;
|
||||
struct include_stack_t*tail = 0;
|
||||
struct include_stack_t*isp = malloc(sizeof(struct include_stack_t));
|
||||
isp->path = strdup(path);
|
||||
isp->file = fopen(path, "r");
|
||||
isp->path = strdup(paths[0]);
|
||||
isp->file = fopen(paths[0], "r");
|
||||
isp->str = 0;
|
||||
if (isp->file == 0) {
|
||||
perror(path);
|
||||
perror(paths[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -525,4 +562,20 @@ void reset_lexor(FILE*out, const char*path)
|
||||
assert(istack == 0);
|
||||
istack = isp;
|
||||
isp->next = 0;
|
||||
|
||||
/* Now build up a queue of all the remaining file names, so
|
||||
that yywrap can pull them when needed. */
|
||||
file_queue = 0;
|
||||
for (idx = 1 ; paths[idx] ; idx += 1) {
|
||||
isp = malloc(sizeof(struct include_stack_t));
|
||||
isp->path = strdup(paths[idx]);
|
||||
isp->str = 0;
|
||||
isp->next = 0;
|
||||
if (tail)
|
||||
tail->next = isp;
|
||||
else
|
||||
file_queue = isp;
|
||||
|
||||
tail = isp;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-3
@@ -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.2 1999/07/03 20:03:47 steve Exp $"
|
||||
#ident "$Id: main.c,v 1.3 1999/09/05 22:33:18 steve Exp $"
|
||||
#endif
|
||||
|
||||
const char NOTICE[] =
|
||||
@@ -109,7 +109,7 @@ int main(int argc, char*argv[])
|
||||
flag_errors += 1;
|
||||
|
||||
if (flag_errors) {
|
||||
fprintf(stderr, "\nUsage: %s [-v][-L][-I<dir>][-D<def>] <file>\n"
|
||||
fprintf(stderr, "\nUsage: %s [-v][-L][-I<dir>][-D<def>] <file>...\n"
|
||||
" -D<def> - Predefine a value.\n"
|
||||
" -I<dir> - Add an include file search directory\n"
|
||||
" -L - Emit line number directives\n"
|
||||
@@ -129,12 +129,20 @@ int main(int argc, char*argv[])
|
||||
out = stdout;
|
||||
}
|
||||
|
||||
reset_lexor(out, argv[optind]);
|
||||
if (argv[optind] == 0) {
|
||||
fprintf(stderr, "%s: No input files given.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
reset_lexor(out, argv+optind);
|
||||
return yyparse();
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: main.c,v $
|
||||
* Revision 1.3 1999/09/05 22:33:18 steve
|
||||
* Take multiple source files on the command line.
|
||||
*
|
||||
* Revision 1.2 1999/07/03 20:03:47 steve
|
||||
* Add include path and line directives.
|
||||
*
|
||||
|
||||
@@ -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.33 1999/07/17 18:25:38 steve Exp $"
|
||||
#ident "$Id: lexor.lex,v 1.36 1999/09/30 04:51:14 steve Exp $"
|
||||
#endif
|
||||
|
||||
//# define YYSTYPE lexval
|
||||
@@ -41,7 +41,7 @@ extern YYLTYPE yylloc;
|
||||
static void reset_lexor();
|
||||
static void line_directive();
|
||||
|
||||
static int check_identifier(const char*name);
|
||||
extern int check_identifier(const char*str, int len);
|
||||
static verinum*make_sized_binary(const char*txt);
|
||||
static verinum*make_sized_dec(const char*txt);
|
||||
static verinum*make_unsized_dec(const char*txt);
|
||||
@@ -128,7 +128,7 @@ W [ \t\b\f\r]+
|
||||
<UDPTABLE>[pPnN01\?\*\-] { return yytext[0]; }
|
||||
|
||||
[a-zA-Z_][a-zA-Z0-9$_]* {
|
||||
int rc = check_identifier(yytext);
|
||||
int rc = check_identifier(yytext, yyleng);
|
||||
if (rc == IDENTIFIER)
|
||||
yylval.text = strdup(yytext);
|
||||
else
|
||||
@@ -150,8 +150,11 @@ W [ \t\b\f\r]+
|
||||
yylval.text = strdup(yytext);
|
||||
return SYSTEM_IDENTIFIER; }
|
||||
|
||||
\.[a-zA-Z_][a-zA-Z0-9$_]* {
|
||||
yylval.text = strdup(yytext+1);
|
||||
\.{W}?[a-zA-Z_][a-zA-Z0-9$_]* {
|
||||
char*cp = yytext+1;
|
||||
while (! (isalpha(*cp) || (*cp == '_')))
|
||||
cp += 1;
|
||||
yylval.text = strdup(cp);
|
||||
return PORTNAME; }
|
||||
|
||||
[0-9][0-9_]*[ \t]*\'d[ \t]*[0-9][0-9_]* {
|
||||
@@ -305,118 +308,6 @@ void lex_end_table()
|
||||
BEGIN(INITIAL);
|
||||
}
|
||||
|
||||
static const struct { const char*name; int code; } key_table[] = {
|
||||
{ "always", K_always },
|
||||
{ "and", K_and },
|
||||
{ "assign", K_assign },
|
||||
{ "begin", K_begin },
|
||||
{ "buf", K_buf },
|
||||
{ "bufif0", K_bufif0 },
|
||||
{ "bufif1", K_bufif1 },
|
||||
{ "case", K_case },
|
||||
{ "casex", K_casex },
|
||||
{ "casez", K_casez },
|
||||
{ "cmos", K_cmos },
|
||||
{ "deassign", K_deassign },
|
||||
{ "default", K_default },
|
||||
{ "defparam", K_defparam },
|
||||
{ "disable", K_disable },
|
||||
{ "edge", K_edge },
|
||||
{ "else", K_else },
|
||||
{ "end", K_end },
|
||||
{ "endcase", K_endcase },
|
||||
{ "endfunction", K_endfunction },
|
||||
{ "endmodule", K_endmodule },
|
||||
{ "endprimitive", K_endprimitive },
|
||||
{ "endspecify", K_endspecify },
|
||||
{ "endtable", K_endtable },
|
||||
{ "endtask", K_endtask },
|
||||
{ "event", K_event },
|
||||
{ "for", K_for },
|
||||
{ "force", K_force },
|
||||
{ "forever", K_forever },
|
||||
{ "fork", K_fork },
|
||||
{ "function", K_function },
|
||||
{ "highz0", K_highz0 },
|
||||
{ "highz1", K_highz1 },
|
||||
{ "if", K_if },
|
||||
{ "initial", K_initial },
|
||||
{ "inout", K_inout },
|
||||
{ "input", K_input },
|
||||
{ "integer", K_integer },
|
||||
{ "join", K_join },
|
||||
{ "large", K_large },
|
||||
{ "macromodule", K_macromodule },
|
||||
{ "medium", K_medium },
|
||||
{ "module", K_module },
|
||||
{ "nand", K_nand },
|
||||
{ "negedge", K_negedge },
|
||||
{ "nmos", K_nmos },
|
||||
{ "nor", K_nor },
|
||||
{ "not", K_not },
|
||||
{ "notif0", K_notif0 },
|
||||
{ "notif1", K_notif1 },
|
||||
{ "or", K_or },
|
||||
{ "output", K_output },
|
||||
{ "parameter", K_parameter },
|
||||
{ "pmos", K_pmos },
|
||||
{ "posedge", K_posedge },
|
||||
{ "primitive", K_primitive },
|
||||
{ "pull0", K_pull0 },
|
||||
{ "pull1", K_pull1 },
|
||||
{ "pulldown", K_pulldown },
|
||||
{ "pullup", K_pullup },
|
||||
{ "rcmos", K_rcmos },
|
||||
{ "reg", K_reg },
|
||||
{ "release", K_release },
|
||||
{ "repeat", K_repeat },
|
||||
{ "rnmos", K_rnmos },
|
||||
{ "rpmos", K_rpmos },
|
||||
{ "rtran", K_rtran },
|
||||
{ "rtranif0", K_rtranif0 },
|
||||
{ "rtranif1", K_rtranif1 },
|
||||
{ "scalered", K_scalered },
|
||||
{ "small", K_small },
|
||||
{ "specify", K_specify },
|
||||
{ "specparam", K_specparam },
|
||||
{ "strong0", K_strong0 },
|
||||
{ "strong1", K_strong1 },
|
||||
{ "supply0", K_supply0 },
|
||||
{ "supply1", K_supply1 },
|
||||
{ "table", K_table },
|
||||
{ "task", K_task },
|
||||
{ "time", K_time },
|
||||
{ "tran", K_tran },
|
||||
{ "tranif0", K_tranif0 },
|
||||
{ "tranif1", K_tranif1 },
|
||||
{ "tri", K_tri },
|
||||
{ "tri0", K_tri0 },
|
||||
{ "tri1", K_tri1 },
|
||||
{ "triand", K_triand },
|
||||
{ "trior", K_trior },
|
||||
{ "trireg", K_trireg },
|
||||
{ "vectored", K_vectored },
|
||||
{ "wait", K_wait },
|
||||
{ "wand", K_wand },
|
||||
{ "weak0", K_weak0 },
|
||||
{ "weak1", K_weak1 },
|
||||
{ "while", K_while },
|
||||
{ "wire", K_wire },
|
||||
{ "wor", K_wor },
|
||||
{ "xnor", K_xnor },
|
||||
{ "xor", K_xor },
|
||||
{ 0, IDENTIFIER }
|
||||
};
|
||||
|
||||
static int check_identifier(const char*name)
|
||||
{
|
||||
for (unsigned idx = 0 ; key_table[idx].name ; idx += 1)
|
||||
if (strcmp(key_table[idx].name, name) == 0)
|
||||
return key_table[idx].code;
|
||||
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
|
||||
{
|
||||
assert(tolower(*ptr) == 'b');
|
||||
@@ -540,47 +431,77 @@ static verinum*make_sized_octal(const char*txt)
|
||||
ptr += 1;
|
||||
assert(tolower(*ptr) == 'o');
|
||||
|
||||
/* We know from the size number how bit to make the verinom
|
||||
array, so make it now. */
|
||||
verinum::V*bits = new verinum::V[size];
|
||||
|
||||
/* skip white space between size and the base token. */
|
||||
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
|
||||
ptr += 1;
|
||||
|
||||
unsigned idx = 0;
|
||||
/* Find the end of the digits. ptr already points to the start. */
|
||||
char*eptr = ptr + strlen(ptr);
|
||||
|
||||
while ((eptr > ptr) && (idx < (size-3))) {
|
||||
switch (*eptr) {
|
||||
/* From the last digit and forward, build up the number, least
|
||||
significant bit first. This loop will not get the last few
|
||||
bits if the size is not a multiple of 3. */
|
||||
unsigned idx = 0;
|
||||
while ((eptr > ptr) && ((idx/3) < (size/3))) switch (*--eptr) {
|
||||
|
||||
case 'x': case 'X':
|
||||
bits[idx++] = verinum::Vx;
|
||||
bits[idx++] = verinum::Vx;
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
|
||||
case 'z': case 'Z': case '?':
|
||||
bits[idx++] = verinum::Vz;
|
||||
bits[idx++] = verinum::Vz;
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
|
||||
default: {
|
||||
unsigned val = *eptr - '0';
|
||||
bits[idx++] = (val&1)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&2)? verinum::V1 : verinum::V0;
|
||||
bits[idx++] = (val&4)? verinum::V1 : verinum::V0;
|
||||
}
|
||||
}
|
||||
|
||||
eptr -= 1;
|
||||
}
|
||||
|
||||
// zero extend octal numbers
|
||||
while (idx < size) switch (ptr[1]) {
|
||||
if ((eptr > ptr) && (idx < size)) switch (*--eptr) {
|
||||
|
||||
case 'x': case 'X':
|
||||
bits[idx++] = verinum::Vx;
|
||||
for ( ; idx < size ; idx += 1)
|
||||
bits[idx] = verinum::Vx;
|
||||
break;
|
||||
|
||||
case 'z': case 'Z': case '?':
|
||||
bits[idx++] = verinum::Vz;
|
||||
for ( ; idx < size ; idx += 1)
|
||||
bits[idx] = verinum::Vz;
|
||||
break;
|
||||
default:
|
||||
bits[idx++] = verinum::V0;
|
||||
|
||||
default: {
|
||||
unsigned val = *eptr - '0';
|
||||
for ( ; idx < size ; idx += 1) {
|
||||
bits[idx] = (val&1)? verinum::V1 : verinum::V0;
|
||||
val >>= 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// zero extend octal numbers
|
||||
while (idx < size) switch (ptr[1]) {
|
||||
case 'x': case 'X':
|
||||
bits[idx++] = verinum::Vx;
|
||||
break;
|
||||
case 'z': case 'Z': case '?':
|
||||
bits[idx++] = verinum::Vz;
|
||||
break;
|
||||
default:
|
||||
bits[idx++] = verinum::V0;
|
||||
}
|
||||
}
|
||||
|
||||
return new verinum(bits, size, true);
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/* C code produced by gperf version 2.7 */
|
||||
/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf > lexor_keyword.cc */
|
||||
|
||||
#include "parse_misc.h"
|
||||
#include "parse.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define TOTAL_KEYWORDS 99
|
||||
#define MIN_WORD_LENGTH 2
|
||||
#define MAX_WORD_LENGTH 12
|
||||
#define MIN_HASH_VALUE 7
|
||||
#define MAX_HASH_VALUE 239
|
||||
/* maximum key range = 233, duplicates = 0 */
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#endif
|
||||
static unsigned int
|
||||
keyword_hash (const char *str, int len)
|
||||
{
|
||||
static const unsigned char asso_values[] =
|
||||
{
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 126, 66,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 31, 11, 81,
|
||||
1, 1, 81, 26, 11, 51, 11, 21, 81, 81,
|
||||
1, 46, 16, 240, 1, 1, 6, 11, 36, 46,
|
||||
21, 16, 6, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
|
||||
240, 240, 240, 240, 240, 240
|
||||
};
|
||||
int hval = len;
|
||||
|
||||
hval += asso_values[(unsigned char)str[len - 1]];
|
||||
hval += asso_values[(unsigned char)str[0]];
|
||||
hval += asso_values[(unsigned char)str[1]];
|
||||
|
||||
if (len > 2)
|
||||
hval += asso_values[(unsigned char)str[2]];
|
||||
|
||||
return hval ;
|
||||
}
|
||||
|
||||
int
|
||||
check_identifier (const char *str, int len)
|
||||
{
|
||||
static const struct { const char *name; int tokenType; } wordlist[] =
|
||||
{
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{"end", K_end},
|
||||
{""}, {""}, {""},
|
||||
{"endcase", K_endcase},
|
||||
{"endtable", K_endtable},
|
||||
{"endmodule", K_endmodule},
|
||||
{"rtran", K_rtran},
|
||||
{"endfunction", K_endfunction},
|
||||
{"endprimitive", K_endprimitive},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{""}, {""}, {""},
|
||||
{"endspecify", K_endspecify},
|
||||
{"repeat", K_repeat},
|
||||
{"endtask", K_endtask},
|
||||
{""},
|
||||
{"edge", K_edge},
|
||||
{""}, {""},
|
||||
{"negedge", K_negedge},
|
||||
{"and", K_and},
|
||||
{"nand", K_nand},
|
||||
{""},
|
||||
{"assign", K_assign},
|
||||
{"specify", K_specify},
|
||||
{"deassign", K_deassign},
|
||||
{"tran", K_tran},
|
||||
{"begin", K_begin},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"event", K_event},
|
||||
{"or", K_or},
|
||||
{""},
|
||||
{"nor", K_nor},
|
||||
{""},
|
||||
{"table", K_table},
|
||||
{""}, {""},
|
||||
{"reg", K_reg},
|
||||
{"parameter", K_parameter},
|
||||
{""}, {""},
|
||||
{"disable", K_disable},
|
||||
{"not", K_not},
|
||||
{"task", K_task},
|
||||
{"trior", K_trior},
|
||||
{"triand", K_triand},
|
||||
{"integer", K_integer},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"posedge", K_posedge},
|
||||
{"xor", K_xor},
|
||||
{"xnor", K_xnor},
|
||||
{""},
|
||||
{"output", K_output},
|
||||
{""}, {""},
|
||||
{"primitive", K_primitive},
|
||||
{"input", K_input},
|
||||
{""},
|
||||
{"strong1", K_strong1},
|
||||
{"rtranif1", K_rtranif1},
|
||||
{"wand", K_wand},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"else", K_else},
|
||||
{"rnmos", K_rnmos},
|
||||
{"trireg", K_trireg},
|
||||
{"release", K_release},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"default", K_default},
|
||||
{"wor", K_wor},
|
||||
{""}, {""}, {""},
|
||||
{"supply1", K_supply1},
|
||||
{"function", K_function},
|
||||
{"wire", K_wire},
|
||||
{"rpmos", K_rpmos},
|
||||
{""}, {""}, {""},
|
||||
{"specparam", K_specparam},
|
||||
{"inout", K_inout},
|
||||
{""},
|
||||
{"tranif1", K_tranif1},
|
||||
{"tri", K_tri},
|
||||
{"join", K_join},
|
||||
{"while", K_while},
|
||||
{""}, {""},
|
||||
{"pulldown", K_pulldown},
|
||||
{"case", K_case},
|
||||
{"large", K_large},
|
||||
{""}, {""},
|
||||
{"scalered", K_scalered},
|
||||
{""},
|
||||
{"casez", K_casez},
|
||||
{"notif1", K_notif1},
|
||||
{""},
|
||||
{"vectored", K_vectored},
|
||||
{"tri1", K_tri1},
|
||||
{""},
|
||||
{"pullup", K_pullup},
|
||||
{""},
|
||||
{"for", K_for},
|
||||
{"nmos", K_nmos},
|
||||
{"force", K_force},
|
||||
{"module", K_module},
|
||||
{"forever", K_forever},
|
||||
{""},
|
||||
{"wait", K_wait},
|
||||
{"casex", K_casex},
|
||||
{""},
|
||||
{"strong0", K_strong0},
|
||||
{"rtranif0", K_rtranif0},
|
||||
{"time", K_time},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"pmos", K_pmos},
|
||||
{"weak1", K_weak1},
|
||||
{""}, {""}, {""},
|
||||
{"fork", K_fork},
|
||||
{""}, {""}, {""}, {""}, {""}, {""},
|
||||
{"highz1", K_highz1},
|
||||
{"supply0", K_supply0},
|
||||
{""}, {""}, {""},
|
||||
{"always", K_always},
|
||||
{""}, {""}, {""},
|
||||
{"rcmos", K_rcmos},
|
||||
{"medium", K_medium},
|
||||
{"tranif0", K_tranif0},
|
||||
{"defparam", K_defparam},
|
||||
{""}, {""},
|
||||
{"bufif1", K_bufif1},
|
||||
{""}, {""}, {""},
|
||||
{"pull1", K_pull1},
|
||||
{""}, {""}, {""}, {""}, {""},
|
||||
{"notif0", K_notif0},
|
||||
{""},
|
||||
{"buf", K_buf},
|
||||
{"tri0", K_tri0},
|
||||
{""}, {""},
|
||||
{"initial", K_initial},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{"small", K_small},
|
||||
{""}, {""}, {""}, {""}, {""},
|
||||
{"macromodule", K_macromodule},
|
||||
{""}, {""}, {""},
|
||||
{"weak0", K_weak0},
|
||||
{""}, {""}, {""},
|
||||
{"cmos", K_cmos},
|
||||
{""},
|
||||
{"if", K_if},
|
||||
{""}, {""}, {""}, {""},
|
||||
{"highz0", K_highz0},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{""}, {""}, {""}, {""}, {""},
|
||||
{"bufif0", K_bufif0},
|
||||
{""}, {""}, {""},
|
||||
{"pull0", K_pull0}
|
||||
};
|
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
||||
{
|
||||
int key = keyword_hash (str, len);
|
||||
|
||||
if (key <= MAX_HASH_VALUE && key >= 0)
|
||||
{
|
||||
const char *s = wordlist[key].name;
|
||||
|
||||
if (*str == *s && !strcmp (str + 1, s + 1))
|
||||
return wordlist[key].tokenType;
|
||||
}
|
||||
}
|
||||
return IDENTIFIER;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
%{
|
||||
/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf */
|
||||
|
||||
#include "parse_misc.h"
|
||||
#include "parse.h"
|
||||
#include <string.h>
|
||||
|
||||
%}
|
||||
struct Keywords {
|
||||
char *name;
|
||||
int tokenType;
|
||||
} Keywords;
|
||||
%%
|
||||
always, K_always
|
||||
and, K_and
|
||||
assign, K_assign
|
||||
begin, K_begin
|
||||
buf, K_buf
|
||||
bufif0, K_bufif0
|
||||
bufif1, K_bufif1
|
||||
case, K_case
|
||||
casex, K_casex
|
||||
casez, K_casez
|
||||
cmos, K_cmos
|
||||
deassign, K_deassign
|
||||
default, K_default
|
||||
defparam, K_defparam
|
||||
disable, K_disable
|
||||
edge, K_edge
|
||||
else, K_else
|
||||
end, K_end
|
||||
endcase, K_endcase
|
||||
endfunction, K_endfunction
|
||||
endmodule, K_endmodule
|
||||
endprimitive, K_endprimitive
|
||||
endspecify, K_endspecify
|
||||
endtable, K_endtable
|
||||
endtask, K_endtask
|
||||
event, K_event
|
||||
for, K_for
|
||||
force, K_force
|
||||
forever, K_forever
|
||||
fork, K_fork
|
||||
function, K_function
|
||||
highz0, K_highz0
|
||||
highz1, K_highz1
|
||||
if, K_if
|
||||
initial, K_initial
|
||||
inout, K_inout
|
||||
input, K_input
|
||||
integer, K_integer
|
||||
join, K_join
|
||||
large, K_large
|
||||
macromodule, K_macromodule
|
||||
medium, K_medium
|
||||
module, K_module
|
||||
nand, K_nand
|
||||
negedge, K_negedge
|
||||
nmos, K_nmos
|
||||
nor, K_nor
|
||||
not, K_not
|
||||
notif0, K_notif0
|
||||
notif1, K_notif1
|
||||
or, K_or
|
||||
output, K_output
|
||||
parameter, K_parameter
|
||||
pmos, K_pmos
|
||||
posedge, K_posedge
|
||||
primitive, K_primitive
|
||||
pull0, K_pull0
|
||||
pull1, K_pull1
|
||||
pulldown, K_pulldown
|
||||
pullup, K_pullup
|
||||
rcmos, K_rcmos
|
||||
reg, K_reg
|
||||
release, K_release
|
||||
repeat, K_repeat
|
||||
rnmos, K_rnmos
|
||||
rpmos, K_rpmos
|
||||
rtran, K_rtran
|
||||
rtranif0, K_rtranif0
|
||||
rtranif1, K_rtranif1
|
||||
scalered, K_scalered
|
||||
small, K_small
|
||||
specify, K_specify
|
||||
specparam, K_specparam
|
||||
strong0, K_strong0
|
||||
strong1, K_strong1
|
||||
supply0, K_supply0
|
||||
supply1, K_supply1
|
||||
table, K_table
|
||||
task, K_task
|
||||
time, K_time
|
||||
tran, K_tran
|
||||
tranif0, K_tranif0
|
||||
tranif1, K_tranif1
|
||||
tri, K_tri
|
||||
tri0, K_tri0
|
||||
tri1, K_tri1
|
||||
triand, K_triand
|
||||
trior, K_trior
|
||||
trireg, K_trireg
|
||||
vectored, K_vectored
|
||||
wait, K_wait
|
||||
wand, K_wand
|
||||
weak0, K_weak0
|
||||
weak1, K_weak1
|
||||
while, K_while
|
||||
wire, K_wire
|
||||
wor, K_wor
|
||||
xnor, K_xnor
|
||||
xor, K_xor
|
||||
@@ -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.22 1999/08/03 04:14:49 steve Exp $"
|
||||
#ident "$Id: main.cc,v 1.23 1999/09/22 16:57:23 steve Exp $"
|
||||
#endif
|
||||
|
||||
const char NOTICE[] =
|
||||
@@ -75,7 +75,6 @@ static void parm_to_flagmap(const string&flag)
|
||||
extern Design* elaborate(const map<string,Module*>&modules,
|
||||
const map<string,PUdp*>&primitives,
|
||||
const string&root);
|
||||
extern void emit(ostream&o, const Design*, const char*);
|
||||
|
||||
extern void cprop(Design*des);
|
||||
extern void propinit(Design*des);
|
||||
@@ -252,6 +251,7 @@ int main(int argc, char*argv[])
|
||||
}
|
||||
|
||||
|
||||
bool emit_rc;
|
||||
if (out_path) {
|
||||
ofstream out;
|
||||
out.open(out_path);
|
||||
@@ -261,10 +261,15 @@ int main(int argc, char*argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
emit(out, des, target);
|
||||
emit_rc = emit(out, des, target);
|
||||
|
||||
} else {
|
||||
emit(cout, des, target);
|
||||
emit_rc = emit(cout, des, target);
|
||||
}
|
||||
|
||||
if (!emit_rc) {
|
||||
cerr << "internal error: Code generation had errors." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -272,6 +277,9 @@ int main(int argc, char*argv[])
|
||||
|
||||
/*
|
||||
* $Log: main.cc,v $
|
||||
* Revision 1.23 1999/09/22 16:57:23 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.22 1999/08/03 04:14:49 steve
|
||||
* Parse into pform arbitrarily complex module
|
||||
* port declarations.
|
||||
|
||||
+510
-272
File diff suppressed because it is too large
Load Diff
@@ -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.55 1999/08/06 04:05:28 steve Exp $"
|
||||
#ident "$Id: netlist.h,v 1.78 1999/10/07 05:25:34 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -40,6 +40,7 @@ class NetNode;
|
||||
class NetProc;
|
||||
class NetProcTop;
|
||||
class NetExpr;
|
||||
class NetESignal;
|
||||
class ostream;
|
||||
|
||||
|
||||
@@ -169,8 +170,8 @@ class NetObj {
|
||||
bool test_mark() const { return mark_; }
|
||||
void set_mark(bool flag=true) { mark_ = flag; }
|
||||
|
||||
Link&pin(unsigned idx) { return pins_[idx]; }
|
||||
const Link&pin(unsigned idx) const { return pins_[idx]; }
|
||||
Link&pin(unsigned idx);
|
||||
const Link&pin(unsigned idx) const;
|
||||
|
||||
void dump_node_pins(ostream&, unsigned) const;
|
||||
void dump_obj_attr(ostream&, unsigned) const;
|
||||
@@ -219,7 +220,8 @@ class NetNode : public NetObj {
|
||||
*
|
||||
* Note that a net of any sort has exactly one pin. The pins feature
|
||||
* of the NetObj class is used to make a set of identical wires, in
|
||||
* order to support ranges, or busses.
|
||||
* order to support ranges, or busses. When dealing with vectors,
|
||||
* pin(0) is always the least significant bit.
|
||||
*/
|
||||
class NetNet : public NetObj, public LineInfo {
|
||||
|
||||
@@ -242,15 +244,17 @@ class NetNet : public NetObj, public LineInfo {
|
||||
PortType port_type() const { return port_type_; }
|
||||
void port_type(PortType t) { port_type_ = t; }
|
||||
|
||||
/* These methods return the msb and lsb indices for the most
|
||||
significant and least significant bits. These are signed
|
||||
longs, and may be different from pin numbers. For example,
|
||||
reg [1:8] has 8 bits, msb==1 and lsb==8. */
|
||||
long msb() const { return msb_; }
|
||||
long lsb() const { return lsb_; }
|
||||
|
||||
unsigned sb_to_idx(long sb) const
|
||||
{ if (msb_ >= lsb_)
|
||||
return sb - lsb_;
|
||||
else
|
||||
return lsb_ - sb;
|
||||
}
|
||||
/* This method converts a signed index (the type that might be
|
||||
found in the verilog source) to a pin number. It accounts
|
||||
for variation in the definition of the reg/wire/whatever. */
|
||||
unsigned sb_to_idx(long sb) const;
|
||||
|
||||
bool local_flag() const { return local_flag_; }
|
||||
void local_flag(bool f) { local_flag_ = f; }
|
||||
@@ -279,6 +283,36 @@ class NetNet : public NetObj, public LineInfo {
|
||||
verinum::V*ivalue_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class implements the LPM_ADD_SUB component as described in the
|
||||
* EDIF LPM Version 2 1 0 standard. It is used as a structural
|
||||
* implementation of the + and - operators.
|
||||
*/
|
||||
class NetAddSub : public NetNode {
|
||||
|
||||
public:
|
||||
NetAddSub(const string&n, unsigned width);
|
||||
~NetAddSub();
|
||||
|
||||
// Get the width of the device (that is, the width of the
|
||||
// operands and results.)
|
||||
unsigned width() const;
|
||||
|
||||
NetObj::Link& pin_Aclr();
|
||||
NetObj::Link& pin_Add_Sub();
|
||||
NetObj::Link& pin_Clock();
|
||||
NetObj::Link& pin_Cin();
|
||||
NetObj::Link& pin_Cout();
|
||||
NetObj::Link& pin_Overflow();
|
||||
|
||||
NetObj::Link& pin_DataA(unsigned idx);
|
||||
NetObj::Link& pin_DataB(unsigned idx);
|
||||
NetObj::Link& pin_Result(unsigned idx);
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class represents the declared memory object. The parser
|
||||
* creates one of these for each declared memory in the elaborated
|
||||
@@ -330,7 +364,7 @@ class NetMemory {
|
||||
*/
|
||||
class NetExpr : public LineInfo {
|
||||
public:
|
||||
explicit NetExpr(unsigned w =0) : width_(w) { }
|
||||
explicit NetExpr(unsigned w =0);
|
||||
virtual ~NetExpr() =0;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const =0;
|
||||
@@ -438,7 +472,7 @@ class NetLogic : public NetNode {
|
||||
* expand it out any further then this in the netlist, as this can be
|
||||
* used to represent target device primitives.
|
||||
*
|
||||
* The UDP can be combinational or sequential. The sequentianl UDP
|
||||
* The UDP can be combinational or sequential. The sequential UDP
|
||||
* includes the current output in the truth table, and supports edges,
|
||||
* whereas the combinational does not and is entirely level sensitive.
|
||||
* In any case, pin 0 is an output, and all the remaining pins are
|
||||
@@ -549,13 +583,16 @@ class NetUDP : public NetNode {
|
||||
* linked into the netlist. However, elaborating a process may cause
|
||||
* special nodes to be created to handle things like events.
|
||||
*/
|
||||
class NetProc {
|
||||
class NetProc : public LineInfo {
|
||||
|
||||
public:
|
||||
explicit NetProc() : next_(0) { }
|
||||
explicit NetProc();
|
||||
virtual ~NetProc();
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
// This method is called to emit the statement to the
|
||||
// target. The target returns true if OK, false for errors.
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -570,33 +607,51 @@ class NetProc {
|
||||
* lvalue object and represents the elaborated lvalue. Thus, this
|
||||
* appears as a procedural statement AND a structural node. The
|
||||
* LineInfo is the location of the assignment statement in the source.
|
||||
*
|
||||
* NOTE: The elaborator will make an effort to match the width of the
|
||||
* r-value to the with of the assign node, but targets and functions
|
||||
* should know that this is not a guarantee.
|
||||
*/
|
||||
|
||||
class NetAssign_ : public NetProc, public NetNode, public LineInfo {
|
||||
class NetAssign_ : public NetProc, public NetNode {
|
||||
|
||||
public:
|
||||
|
||||
// This is the (procedural) value that is to be assigned when
|
||||
// the assignment is executed.
|
||||
NetExpr*rval();
|
||||
const NetExpr*rval() const;
|
||||
|
||||
// If this expression exists, then only a single bit is to be
|
||||
// set from the rval, and the value of this expression selects
|
||||
// the pin that gets the value.
|
||||
const NetExpr*bmux() const;
|
||||
|
||||
protected:
|
||||
NetAssign_(const string&n, unsigned w);
|
||||
virtual ~NetAssign_() =0;
|
||||
|
||||
void set_rval(NetExpr*);
|
||||
void set_bmux(NetExpr*);
|
||||
|
||||
private:
|
||||
NetExpr*rval_;
|
||||
NetExpr*bmux_;
|
||||
};
|
||||
|
||||
class NetAssign : public NetAssign_ {
|
||||
public:
|
||||
explicit NetAssign(const string&, Design*des, unsigned w, NetExpr*rv);
|
||||
explicit NetAssign(const string&, Design*des, unsigned w,
|
||||
NetExpr*mux, NetExpr*rv);
|
||||
~NetAssign();
|
||||
|
||||
NetExpr*rval() { return rval_; }
|
||||
const NetExpr*rval() const { return rval_; }
|
||||
|
||||
void find_lval_range(const NetNet*&net, unsigned&msb,
|
||||
unsigned&lsb) const;
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
NetExpr* rval_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -609,48 +664,61 @@ class NetAssignNB : public NetAssign_ {
|
||||
NetExpr*mux, NetExpr*rv);
|
||||
~NetAssignNB();
|
||||
|
||||
// This is the (procedural) value that is to be assigned when
|
||||
// the assignment is executed.
|
||||
const NetExpr*rval() const { return rval_; }
|
||||
|
||||
// If this expression exists, then only a single bit is to be
|
||||
// set from the rval, and the value of this expression selects
|
||||
// the pin that gets the value.
|
||||
const NetExpr*bmux() const { return bmux_; }
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void emit_node(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
NetExpr* rval_;
|
||||
NetExpr* bmux_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Assignment to memory is handled separately because memory is
|
||||
* not a node.
|
||||
* not a node. There are blocking and non-blocking variants, just like
|
||||
* regular assign, and the NetAssignMem_ base class takes care of all
|
||||
* the common stuff.
|
||||
*/
|
||||
class NetAssignMem : public NetProc, public LineInfo {
|
||||
class NetAssignMem_ : public NetProc {
|
||||
|
||||
public:
|
||||
explicit NetAssignMem(NetMemory*, NetExpr*idx, NetExpr*rv);
|
||||
~NetAssignMem();
|
||||
explicit NetAssignMem_(NetMemory*, NetExpr*idx, NetExpr*rv);
|
||||
~NetAssignMem_();
|
||||
|
||||
const NetMemory*memory()const { return mem_; }
|
||||
const NetExpr*index()const { return index_; }
|
||||
const NetExpr*rval()const { return rval_; }
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
NetMemory*mem_;
|
||||
NetExpr* index_;
|
||||
NetExpr* rval_;
|
||||
};
|
||||
|
||||
class NetAssignMem : public NetAssignMem_ {
|
||||
|
||||
public:
|
||||
explicit NetAssignMem(NetMemory*, NetExpr*idx, NetExpr*rv);
|
||||
~NetAssignMem();
|
||||
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class NetAssignMemNB : public NetAssignMem_ {
|
||||
|
||||
public:
|
||||
explicit NetAssignMemNB(NetMemory*, NetExpr*idx, NetExpr*rv);
|
||||
~NetAssignMemNB();
|
||||
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
/* A block is stuff line begin-end blocks, that contain and ordered
|
||||
list of NetProc statements.
|
||||
|
||||
@@ -670,7 +738,7 @@ class NetBlock : public NetProc {
|
||||
void append(NetProc*);
|
||||
|
||||
void emit_recurse(ostream&, struct target_t*) const;
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -679,29 +747,40 @@ class NetBlock : public NetProc {
|
||||
NetProc*last_;
|
||||
};
|
||||
|
||||
/* A CASE statement in the verilog source leads, eventually, to one of
|
||||
these. This is different from a simple conditional because of the
|
||||
way the comparisons are performed. Also, it is likely that the
|
||||
target may be able to optimize differently. */
|
||||
/*
|
||||
* A CASE statement in the verilog source leads, eventually, to one of
|
||||
* these. This is different from a simple conditional because of the
|
||||
* way the comparisons are performed. Also, it is likely that the
|
||||
* target may be able to optimize differently.
|
||||
*
|
||||
* Case cane be one of three types:
|
||||
* EQ -- All bits must exactly match
|
||||
* EQZ -- z bits are don't care
|
||||
* EQX -- x and z bits are don't care.
|
||||
*/
|
||||
class NetCase : public NetProc {
|
||||
|
||||
public:
|
||||
NetCase(NetExpr*ex, unsigned cnt);
|
||||
enum TYPE { EQ, EQX, EQZ };
|
||||
NetCase(TYPE c, NetExpr*ex, unsigned cnt);
|
||||
~NetCase();
|
||||
|
||||
void set_case(unsigned idx, NetExpr*ex, NetProc*st);
|
||||
|
||||
TYPE type() const;
|
||||
const NetExpr*expr() const { return expr_; }
|
||||
unsigned nitems() const { return nitems_; }
|
||||
|
||||
const NetExpr*expr(unsigned idx) const { return items_[idx].guard;}
|
||||
const NetProc*stat(unsigned idx) const { return items_[idx].statement; }
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
|
||||
TYPE type_;
|
||||
|
||||
struct Item {
|
||||
NetExpr*guard;
|
||||
NetProc*statement;
|
||||
@@ -730,7 +809,7 @@ class NetCondit : public NetProc {
|
||||
void emit_recurse_if(ostream&, struct target_t*) const;
|
||||
void emit_recurse_else(ostream&, struct target_t*) const;
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -751,13 +830,41 @@ class NetForever : public NetProc {
|
||||
|
||||
void emit_recurse(ostream&, struct target_t*) const;
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
NetProc*statement_;
|
||||
};
|
||||
|
||||
/*
|
||||
* A funciton definition is elaborated just like a task, though by now
|
||||
* it is certain that the first parameter (a phantom parameter) is the
|
||||
* output and all the remaining parameters are the inputs. This makes
|
||||
* for easy code generation in targets that support behavioral descriptions.
|
||||
*/
|
||||
class NetFuncDef {
|
||||
|
||||
public:
|
||||
NetFuncDef(const string&, const svector<NetNet*>&po);
|
||||
~NetFuncDef();
|
||||
|
||||
void set_proc(NetProc*st);
|
||||
|
||||
const string& name() const;
|
||||
const NetProc*proc() const;
|
||||
|
||||
unsigned port_count() const;
|
||||
const NetNet*port(unsigned idx) const;
|
||||
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
NetProc*statement_;
|
||||
svector<NetNet*>ports_;
|
||||
};
|
||||
|
||||
class NetPDelay : public NetProc {
|
||||
|
||||
public:
|
||||
@@ -766,7 +873,7 @@ class NetPDelay : public NetProc {
|
||||
|
||||
unsigned long delay() const { return delay_; }
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
void emit_proc_recurse(ostream&, struct target_t*) const;
|
||||
@@ -796,7 +903,7 @@ class NetPEvent : public NetProc, public sref_back<NetPEvent,NetNEvent> {
|
||||
NetProc* statement();
|
||||
const NetProc* statement() const;
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
void emit_proc_recurse(ostream&, struct target_t*) const;
|
||||
@@ -846,7 +953,7 @@ class NetRepeat : public NetProc {
|
||||
const NetExpr*expr() const;
|
||||
void emit_recurse(ostream&, struct target_t*) const;
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -872,7 +979,7 @@ class NetSTask : public NetProc {
|
||||
|
||||
const NetExpr* parm(unsigned idx) const;
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -888,9 +995,11 @@ class NetSTask : public NetProc {
|
||||
class NetTaskDef {
|
||||
|
||||
public:
|
||||
NetTaskDef(const string&n, NetProc*p, const svector<NetNet*>&po);
|
||||
NetTaskDef(const string&n, const svector<NetNet*>&po);
|
||||
~NetTaskDef();
|
||||
|
||||
void set_proc(NetProc*p);
|
||||
|
||||
const string& name() const { return name_; }
|
||||
const NetProc*proc() const { return proc_; }
|
||||
|
||||
@@ -910,7 +1019,48 @@ class NetTaskDef {
|
||||
};
|
||||
|
||||
/*
|
||||
* A call to a user defined task is elaborated into this object.
|
||||
* This node represents a function call in an expression. The object
|
||||
* contains a pointer to the function definition, which is used to
|
||||
* locate the value register and input expressions.
|
||||
*
|
||||
* The NetNet parameter to the constructor is the *register* NetNet
|
||||
* that receives the result of the function, and the NetExpr list is
|
||||
* the paraneters passed to the function.
|
||||
*/
|
||||
class NetEUFunc : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEUFunc(NetFuncDef*, NetESignal*, svector<NetExpr*>&);
|
||||
~NetEUFunc();
|
||||
|
||||
const string& name() const;
|
||||
|
||||
const NetESignal*result() const;
|
||||
unsigned parm_count() const;
|
||||
const NetExpr* parm(unsigned idx) const;
|
||||
|
||||
const NetFuncDef* definition() const;
|
||||
|
||||
virtual bool set_width(unsigned);
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual NetEUFunc*dup_expr() const;
|
||||
|
||||
private:
|
||||
NetFuncDef*func_;
|
||||
NetESignal*result_;
|
||||
svector<NetExpr*> parms_;
|
||||
|
||||
private: // not implemented
|
||||
NetEUFunc(const NetEUFunc&);
|
||||
NetEUFunc& operator= (const NetEUFunc&);
|
||||
};
|
||||
|
||||
/*
|
||||
* A call to a user defined task is elaborated into this object. This
|
||||
* contains a pointer to the elaborated task definition, but is a
|
||||
* NetProc object so that it can be linked into statements.
|
||||
*/
|
||||
class NetUTask : public NetProc {
|
||||
|
||||
@@ -920,7 +1070,7 @@ class NetUTask : public NetProc {
|
||||
|
||||
const string& name() const { return task_->name(); }
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -942,7 +1092,7 @@ class NetWhile : public NetProc {
|
||||
|
||||
void emit_proc_recurse(ostream&, struct target_t*) const;
|
||||
|
||||
virtual void emit_proc(ostream&, struct target_t*) const;
|
||||
virtual bool emit_proc(ostream&, struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
|
||||
private:
|
||||
@@ -951,9 +1101,11 @@ class NetWhile : public NetProc {
|
||||
};
|
||||
|
||||
|
||||
/* The is the top of any process. It carries the type (initial or
|
||||
always) and a pointer to the statement, probably a block, that
|
||||
makes up the process. */
|
||||
/*
|
||||
* The is the top of any process. It carries the type (initial or
|
||||
* always) and a pointer to the statement, probably a block, that
|
||||
* makes up the process.
|
||||
*/
|
||||
class NetProcTop : public LineInfo {
|
||||
|
||||
public:
|
||||
@@ -967,7 +1119,7 @@ class NetProcTop : public LineInfo {
|
||||
const NetProc*statement() const;
|
||||
|
||||
void dump(ostream&, unsigned ind) const;
|
||||
void emit(ostream&, struct target_t*tgt) const;
|
||||
bool emit(ostream&, struct target_t*tgt) const;
|
||||
|
||||
private:
|
||||
const Type type_;
|
||||
@@ -1000,8 +1152,10 @@ class NetProcTop : public LineInfo {
|
||||
* N -- Case inequality (!==)
|
||||
* a -- Logical AND (&&)
|
||||
* o -- Logical OR (||)
|
||||
* O -- Bit-wise NOR
|
||||
* l -- Left shift (<<)
|
||||
* r -- Right shift (>>)
|
||||
* X -- Bitwise exclusive NOR (~^)
|
||||
*/
|
||||
class NetEBinary : public NetExpr {
|
||||
|
||||
@@ -1016,22 +1170,17 @@ class NetEBinary : public NetExpr {
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
|
||||
// If both of my subexpressions are constants, then I can
|
||||
// probably evaluate this part of the expression at compile
|
||||
// time.
|
||||
virtual NetExpr* eval_tree();
|
||||
|
||||
virtual NetEBinary* dup_expr() const;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
NetExpr*eval_eqeq();
|
||||
|
||||
protected:
|
||||
char op_;
|
||||
NetExpr* left_;
|
||||
NetExpr* right_;
|
||||
|
||||
virtual void eval_sub_tree_();
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1061,6 +1210,8 @@ class NetEBAdd : public NetEBinary {
|
||||
* ^ -- Bit-wise exclusive OR
|
||||
* & -- Bit-wise AND
|
||||
* | -- Bit-wise OR
|
||||
* O -- Bit-wise NOR
|
||||
* X -- Bit-wise XNOR (~^)
|
||||
*/
|
||||
class NetEBBits : public NetEBinary {
|
||||
|
||||
@@ -1092,8 +1243,53 @@ class NetEBComp : public NetEBinary {
|
||||
~NetEBComp();
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetExpr* eval_tree();
|
||||
|
||||
private:
|
||||
NetExpr*eval_eqeq_();
|
||||
NetExpr*eval_leeq_();
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* The binary logical operators are those that return boolean
|
||||
* results. The supported operators are:
|
||||
*
|
||||
* a -- Logical AND (&&)
|
||||
*/
|
||||
class NetEBLogic : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBLogic(char op, NetExpr*l, NetExpr*r);
|
||||
~NetEBLogic();
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetExpr* eval_tree();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The binary logical operators are those that return boolean
|
||||
* results. The supported operators are:
|
||||
*
|
||||
* l -- left shift (<<)
|
||||
* r -- right shift (>>)
|
||||
*/
|
||||
class NetEBShift : public NetEBinary {
|
||||
|
||||
public:
|
||||
NetEBShift(char op, NetExpr*l, NetExpr*r);
|
||||
~NetEBShift();
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetExpr* eval_tree();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This expression node supports the concat expression. This is an
|
||||
* operator that just glues the results of many expressions into a
|
||||
@@ -1106,29 +1302,31 @@ class NetEBComp : public NetEBinary {
|
||||
class NetEConcat : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEConcat(unsigned cnt);
|
||||
NetEConcat(unsigned cnt, unsigned repeat =1);
|
||||
~NetEConcat();
|
||||
|
||||
// Manipulate the parameters.
|
||||
void set(unsigned idx, NetExpr*e);
|
||||
|
||||
unsigned repeat() const { return repeat_; }
|
||||
unsigned nparms() const { return parms_.count() ; }
|
||||
NetExpr* parm(unsigned idx) const { return parms_[idx]; }
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual NetEConcat* dup_expr() const;
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
svector<NetExpr*>parms_;
|
||||
unsigned repeat_;
|
||||
};
|
||||
|
||||
class NetEConst : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEConst(const verinum&val)
|
||||
: NetExpr(val.len()), value_(val) { }
|
||||
explicit NetEConst(const verinum&val);
|
||||
~NetEConst();
|
||||
|
||||
const verinum&value() const { return value_; }
|
||||
@@ -1143,6 +1341,67 @@ class NetEConst : public NetExpr {
|
||||
verinum value_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This clas is a placeholder for a parameter expression. When
|
||||
* parameters are first created, an instance of this object is used to
|
||||
* hold the place where the parameter exression goes. Then, when the
|
||||
* parameters are resolved, these objects are removed.
|
||||
*
|
||||
* If the parameter object is created with a path and name, then the
|
||||
* object represents a reference to a parameter that is known to exist.
|
||||
*/
|
||||
class NetEParam : public NetExpr {
|
||||
public:
|
||||
NetEParam();
|
||||
NetEParam(class Design*des, const string&path, const string&name);
|
||||
~NetEParam();
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual NetExpr* eval_tree();
|
||||
virtual NetEParam* dup_expr() const;
|
||||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
private:
|
||||
Design*des_;
|
||||
string path_;
|
||||
string name_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This node represents a system function call in an expression. The
|
||||
* object contains the name of the system function, which the backend
|
||||
* uses to to VPI matching.
|
||||
*/
|
||||
class NetESFunc : public NetExpr {
|
||||
|
||||
public:
|
||||
NetESFunc(const string&name, NetESignal*, svector<NetExpr*>&);
|
||||
~NetESFunc();
|
||||
|
||||
const string& name() const;
|
||||
|
||||
const NetESignal*result() const;
|
||||
unsigned parm_count() const;
|
||||
const NetExpr* parm(unsigned idx) const;
|
||||
|
||||
virtual bool set_width(unsigned);
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual NetESFunc*dup_expr() const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
NetESignal*result_;
|
||||
svector<NetExpr*> parms_;
|
||||
|
||||
private: // not implemented
|
||||
NetESFunc(const NetESFunc&);
|
||||
NetESFunc& operator= (const NetESFunc&);
|
||||
};
|
||||
|
||||
/*
|
||||
* This class represents the ternary (?:) operator. It has 3
|
||||
* expressions, one of which is a condition used to select which of
|
||||
@@ -1156,6 +1415,10 @@ class NetETernary : public NetExpr {
|
||||
|
||||
virtual bool set_width(unsigned w);
|
||||
|
||||
const NetExpr*cond_expr() const;
|
||||
const NetExpr*true_expr() const;
|
||||
const NetExpr*false_expr() const;
|
||||
|
||||
virtual NetETernary* dup_expr() const;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
@@ -1185,8 +1448,7 @@ class NetETernary : public NetExpr {
|
||||
class NetEUnary : public NetExpr {
|
||||
|
||||
public:
|
||||
NetEUnary(char op, NetExpr*ex)
|
||||
: NetExpr(ex->expr_width()), op_(op), expr_(ex) { }
|
||||
NetEUnary(char op, NetExpr*ex);
|
||||
~NetEUnary();
|
||||
|
||||
char op() const { return op_; }
|
||||
@@ -1339,8 +1601,14 @@ class Design {
|
||||
void add_memory(NetMemory*);
|
||||
NetMemory* find_memory(const string&name);
|
||||
|
||||
// Functions
|
||||
void add_function(const string&n, NetFuncDef*);
|
||||
NetFuncDef* find_function(const string&path, const string&key);
|
||||
NetFuncDef* find_function(const string&path);
|
||||
|
||||
// Tasks
|
||||
void add_task(const string&n, NetTaskDef*);
|
||||
NetTaskDef* find_task(const string&path, const string&name);
|
||||
NetTaskDef* find_task(const string&key);
|
||||
|
||||
// NODES
|
||||
@@ -1354,7 +1622,7 @@ class Design {
|
||||
// Iterate over the design...
|
||||
void dump(ostream&) const;
|
||||
void functor(struct functor_t*);
|
||||
void emit(ostream&, struct target_t*) const;
|
||||
bool emit(ostream&, struct target_t*) const;
|
||||
|
||||
void clear_node_marks();
|
||||
NetNode*find_node(bool (*test)(const NetNode*));
|
||||
@@ -1379,6 +1647,9 @@ class Design {
|
||||
|
||||
map<string,NetMemory*> memories_;
|
||||
|
||||
// List the function definitions in the design.
|
||||
map<string,NetFuncDef*> funcs_;
|
||||
|
||||
// List the task definitions in the design.
|
||||
map<string,NetTaskDef*> tasks_;
|
||||
|
||||
@@ -1440,6 +1711,83 @@ extern ostream& operator << (ostream&, NetNet::Type);
|
||||
|
||||
/*
|
||||
* $Log: netlist.h,v $
|
||||
* Revision 1.78 1999/10/07 05:25:34 steve
|
||||
* Add non-const bit select in l-value of assignment.
|
||||
*
|
||||
* Revision 1.77 1999/10/06 05:06:16 steve
|
||||
* Move the rvalue into NetAssign_ common code.
|
||||
*
|
||||
* Revision 1.76 1999/09/30 21:28:34 steve
|
||||
* Handle mutual reference of tasks by elaborating
|
||||
* task definitions in two passes, like functions.
|
||||
*
|
||||
* Revision 1.75 1999/09/30 02:43:02 steve
|
||||
* Elaborate ~^ and ~| operators.
|
||||
*
|
||||
* Revision 1.74 1999/09/29 18:36:03 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.73 1999/09/28 03:11:30 steve
|
||||
* Get the bit widths of unary operators that return one bit.
|
||||
*
|
||||
* Revision 1.72 1999/09/25 02:57:30 steve
|
||||
* Parse system function calls.
|
||||
*
|
||||
* Revision 1.71 1999/09/23 03:56:57 steve
|
||||
* Support shift operators.
|
||||
*
|
||||
* Revision 1.70 1999/09/23 00:21:55 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.69 1999/09/22 16:57:23 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.68 1999/09/21 00:13:40 steve
|
||||
* Support parameters that reference other paramters.
|
||||
*
|
||||
* Revision 1.67 1999/09/20 02:21:10 steve
|
||||
* Elaborate parameters in phases.
|
||||
*
|
||||
* Revision 1.66 1999/09/18 01:53:08 steve
|
||||
* Detect constant lessthen-equal expressions.
|
||||
*
|
||||
* Revision 1.65 1999/09/16 04:18:15 steve
|
||||
* elaborate concatenation repeats.
|
||||
*
|
||||
* Revision 1.64 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.63 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.62 1999/09/11 04:43:17 steve
|
||||
* Support ternary and <= operators in vvm.
|
||||
*
|
||||
* Revision 1.61 1999/09/08 04:05:30 steve
|
||||
* Allow assign to not match rvalue width.
|
||||
*
|
||||
* Revision 1.60 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* Revision 1.59 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.58 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.57 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.56 1999/08/18 04:00:02 steve
|
||||
* Fixup spelling and some error messages. <[email protected]>
|
||||
*
|
||||
* Revision 1.55 1999/08/06 04:05:28 steve
|
||||
* Handle scope of parameters.
|
||||
*
|
||||
|
||||
+8
-5
@@ -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.3 1999/07/24 02:11:20 steve Exp $"
|
||||
#ident "$Id: netlist.txt,v 1.4 1999/09/29 00:03:27 steve Exp $"
|
||||
|
||||
|
||||
Note that the netlist.h header contains detailed descriptions of how
|
||||
@@ -53,14 +53,14 @@ in the vector.
|
||||
Node and net pins can be connected together via the connect
|
||||
function. Connections are transitive (A==B and B==c means A==C) so
|
||||
connections accumulate on a link as items are connected to it. The
|
||||
descructors for nets and nodes automatically arrange for pins to be
|
||||
destructors for nets and nodes automatically arrange for pins to be
|
||||
disconnected when the item is deleted, so that the netlist can be
|
||||
changed during processing.
|
||||
|
||||
BEHAVIORAL ITEMS: NetProcTop, NetProc and derived classes
|
||||
|
||||
Behavioral items are not in general linked to the netlist. Instead,
|
||||
they represent elabrated behavioral statements. The type of the object
|
||||
they represent elaborated behavioral statements. The type of the object
|
||||
implies what the behavior of the statement does. For example, a
|
||||
NetCondit object represents an ``if'' statement, and carries a
|
||||
condition expression and up to two alternative sub-statements.
|
||||
@@ -105,7 +105,7 @@ structurally as events are like devices that trigger behavioral
|
||||
statements.
|
||||
|
||||
However, typical expressions the behavioral description are
|
||||
represented as a tree of NetExpr nodes. The derived clas of the node
|
||||
represented as a tree of NetExpr nodes. The derived class of the node
|
||||
encodes what kind of operator the node represents.
|
||||
|
||||
EXPRESSION BIT WIDTH
|
||||
@@ -160,7 +160,7 @@ the NetESignal object.
|
||||
|
||||
HIERARCHY IN NETLISTS
|
||||
|
||||
The obvious hierarchical structure of verilog is the module. The
|
||||
The obvious hierarchical structure of Verilog is the module. The
|
||||
Verilog program may contain any number of instantiations of modules in
|
||||
order to form an hierarchical design. However, the elaboration of the
|
||||
design into a netlist erases module boundaries. Modules are expanded
|
||||
@@ -189,6 +189,9 @@ some task calls. C++ programmers recognize this as inlining a task.)
|
||||
|
||||
|
||||
$Log: netlist.txt,v $
|
||||
Revision 1.4 1999/09/29 00:03:27 steve
|
||||
Spelling fixes from Larry.
|
||||
|
||||
Revision 1.3 1999/07/24 02:11:20 steve
|
||||
Elaborate task input ports.
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef __netmisc_H
|
||||
#define __netmisc_H
|
||||
/*
|
||||
* 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: netmisc.h,v 1.1 1999/09/29 00:42:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
|
||||
/*
|
||||
* This funciton transforms an expression by padding the high bits
|
||||
* with V0 until the expression has the desired width. This may mean
|
||||
* not transforming the expression at all, if it is already wide
|
||||
* enough.
|
||||
*/
|
||||
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid);
|
||||
|
||||
|
||||
/*
|
||||
* $Log: netmisc.h,v $
|
||||
* Revision 1.1 1999/09/29 00:42:51 steve
|
||||
* Allow expanding of additive operators.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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: pad_to_width.cc,v 1.1 1999/09/29 00:42:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
|
||||
/*
|
||||
* This funciton transforms an expression by padding the high bits
|
||||
* with V0 until the expression has the desired width. This may mean
|
||||
* not transforming the expression at all, if it is already wide
|
||||
* enough.
|
||||
*/
|
||||
NetExpr*pad_to_width(NetExpr*expr, unsigned wid)
|
||||
{
|
||||
if (wid > expr->expr_width()) {
|
||||
verinum pad(verinum::V0, wid - expr->expr_width());
|
||||
NetEConst*co = new NetEConst(pad);
|
||||
NetEConcat*cc = new NetEConcat(2);
|
||||
cc->set(0, co);
|
||||
cc->set(1, expr);
|
||||
cc->set_width(wid);
|
||||
expr = cc;
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: pad_to_width.cc,v $
|
||||
* Revision 1.1 1999/09/29 00:42:51 steve
|
||||
* Allow expanding of additive operators.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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.58 1999/08/03 04:48:51 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.73 1999/09/30 02:43:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
@@ -109,7 +109,7 @@ extern void lex_end_table();
|
||||
%type <text> net_decl_assign
|
||||
%type <strings> net_decl_assigns
|
||||
|
||||
%type <mport> port port_reference port_reference_list
|
||||
%type <mport> port port_opt port_reference port_reference_list
|
||||
%type <mports> list_of_ports list_of_ports_opt
|
||||
|
||||
%type <wires> task_item task_item_list task_item_list_opt
|
||||
@@ -129,6 +129,7 @@ extern void lex_end_table();
|
||||
%type <expr> delay_value
|
||||
%type <exprs> delay delay_opt delay_value_list
|
||||
%type <exprs> expression_list
|
||||
%type <exprs> assign assign_list
|
||||
|
||||
%type <exprs> range range_opt
|
||||
%type <nettype> net_type
|
||||
@@ -137,17 +138,19 @@ extern void lex_end_table();
|
||||
|
||||
%type <task> task_body
|
||||
%type <function> func_body
|
||||
%type <exprs> range_or_type_opt
|
||||
%type <event_expr> event_expression_list
|
||||
%type <event_expr> event_expression
|
||||
%type <event_statement> event_control
|
||||
%type <statement> statement statement_opt
|
||||
%type <statement_list> statement_list
|
||||
|
||||
%left '?' ':'
|
||||
%right '?' ':'
|
||||
%left K_LOR
|
||||
%left K_LAND
|
||||
%left '|'
|
||||
%left '^'
|
||||
%left '&'
|
||||
%left '^' K_NXOR K_NOR
|
||||
%left '&' K_NAND
|
||||
%left K_EQ K_NE K_CEQ K_CNE
|
||||
%left K_GE K_LE '<' '>'
|
||||
%left K_LS K_RS
|
||||
@@ -155,6 +158,10 @@ extern void lex_end_table();
|
||||
%left '*' '/' '%'
|
||||
%left UNARY_PREC
|
||||
|
||||
/* to resolve dangling else ambiguity: */
|
||||
%nonassoc less_than_K_else
|
||||
%nonassoc K_else
|
||||
|
||||
%%
|
||||
|
||||
source_file
|
||||
@@ -162,9 +169,23 @@ source_file
|
||||
| source_file description
|
||||
;
|
||||
|
||||
/* The block_item_decl is used in function definitions, task
|
||||
definitions, module definitions and named blocks. Wherever a new
|
||||
scope is entered, the source may declare new registers and
|
||||
integers. This rule matches those declarations. The containing
|
||||
rule has presumably set up the scope. */
|
||||
block_item_decl
|
||||
: K_reg range_opt register_variable_list ';'
|
||||
: K_reg range register_variable_list ';'
|
||||
{ pform_set_net_range($3, $2);
|
||||
delete $2;
|
||||
delete $3;
|
||||
}
|
||||
| K_reg register_variable_list ';'
|
||||
{ delete $2; }
|
||||
| K_integer list_of_variables ';'
|
||||
{ pform_set_reg_integer($2);
|
||||
delete $2;
|
||||
}
|
||||
;
|
||||
|
||||
block_item_decls
|
||||
@@ -196,7 +217,7 @@ case_item
|
||||
$$ = tmp;
|
||||
}
|
||||
| error ':' statement_opt
|
||||
{ yyerror(@1, "Incomprehensible case expression.");
|
||||
{ yyerror(@1, "error: Incomprehensible case expression.");
|
||||
yyerrok;
|
||||
}
|
||||
;
|
||||
@@ -230,11 +251,12 @@ defparam_assign
|
||||
: identifier '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
if (!pform_expression_is_constant(tmp)) {
|
||||
yyerror(@3, "parameter value must be constant.");
|
||||
yyerror(@3, "error: parameter value "
|
||||
"must be constant.");
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
yyerror(@1, "Sorry, defparam assignments not supported.");
|
||||
yyerror(@1, "sorry: defparam assignments not supported.");
|
||||
delete $1;
|
||||
delete $3;
|
||||
}
|
||||
@@ -243,8 +265,8 @@ defparam_assign
|
||||
defparam_assign_list
|
||||
: defparam_assign
|
||||
| range defparam_assign
|
||||
{ yyerror(@1, "Ranges in parameter definition "
|
||||
"are not supported.");
|
||||
{ yywarn(@1, "Ranges in parameter definition "
|
||||
"are not supported.");
|
||||
delete $1;
|
||||
}
|
||||
| defparam_assign_list ',' defparam_assign
|
||||
@@ -270,7 +292,7 @@ delay_value
|
||||
: NUMBER
|
||||
{ verinum*tmp = $1;
|
||||
if (tmp == 0) {
|
||||
yyerror(@1, "XXXX internal error: delay.");
|
||||
yyerror(@1, "internal error: delay.");
|
||||
$$ = 0;
|
||||
} else {
|
||||
$$ = new PENumber(tmp);
|
||||
@@ -313,10 +335,10 @@ description
|
||||
|
||||
event_control
|
||||
: '@' IDENTIFIER
|
||||
{ yyerror(@1, "Sorry, event control not supported.");
|
||||
{ yyerror(@1, "sorry: event control not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| '@' '(' event_expression ')'
|
||||
| '@' '(' event_expression_list ')'
|
||||
{ PEventStatement*tmp = new PEventStatement(*$3);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
@@ -324,11 +346,22 @@ event_control
|
||||
$$ = tmp;
|
||||
}
|
||||
| '@' '(' error ')'
|
||||
{ yyerror(@1, "Malformed event control expression.");
|
||||
{ yyerror(@1, "error: Malformed event control expression.");
|
||||
$$ = 0;
|
||||
}
|
||||
;
|
||||
|
||||
event_expression_list
|
||||
: event_expression
|
||||
{ $$ = $1; }
|
||||
| event_expression_list K_or event_expression
|
||||
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
|
||||
delete $1;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
event_expression
|
||||
: K_posedge expression
|
||||
{ PEEvent*tmp = new PEEvent(NetNEvent::POSEDGE, $2);
|
||||
@@ -354,12 +387,6 @@ event_expression
|
||||
(*tl)[0] = tmp;
|
||||
$$ = tl;
|
||||
}
|
||||
| event_expression K_or event_expression
|
||||
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
|
||||
delete $1;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
expression
|
||||
@@ -469,6 +496,18 @@ expression
|
||||
tmp->set_lineno(@2.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expression K_NOR expression
|
||||
{ PEBinary*tmp = new PEBinary('O', $1, $3);
|
||||
tmp->set_file(@2.text);
|
||||
tmp->set_lineno(@2.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expression K_NXOR expression
|
||||
{ PEBinary*tmp = new PEBinary('X', $1, $3);
|
||||
tmp->set_file(@2.text);
|
||||
tmp->set_lineno(@2.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| expression '<' expression
|
||||
{ PEBinary*tmp = new PEBinary('<', $1, $3);
|
||||
tmp->set_file(@2.text);
|
||||
@@ -579,7 +618,7 @@ expr_primary
|
||||
$$ = tmp;
|
||||
}
|
||||
| REALTIME
|
||||
{ yyerror(@1, "Sorry, real constants not supported.");
|
||||
{ yyerror(@1, "sorry: real constants not supported.");
|
||||
delete $1;
|
||||
$$ = 0;
|
||||
}
|
||||
@@ -628,13 +667,15 @@ expr_primary
|
||||
$$ = tmp;
|
||||
}
|
||||
| SYSTEM_IDENTIFIER '(' expression_list ')'
|
||||
{ yyerror(@2, "Sorry, function calls not supported.");
|
||||
$$ = 0;
|
||||
{ PECallFunction*tmp = new PECallFunction($1, *$3);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| '(' expression ')'
|
||||
{ $$ = $2; }
|
||||
| '(' expression ':' expression ':' expression ')'
|
||||
{ yyerror(@2, "Sorry, (min:typ:max) not supported.");
|
||||
{ yyerror(@2, "sorry: (min:typ:max) not supported.");
|
||||
$$ = $4;
|
||||
delete $2;
|
||||
delete $6;
|
||||
@@ -649,7 +690,8 @@ expr_primary
|
||||
| '{' expression '{' expression_list '}' '}'
|
||||
{ PExpr*rep = $2;
|
||||
if (!pform_expression_is_constant($2)) {
|
||||
yyerror(@2, "Repeat expression must be constant.");
|
||||
yyerror(@2, "error: Repeat expression "
|
||||
"must be constant.");
|
||||
delete rep;
|
||||
delete $2;
|
||||
rep = 0;
|
||||
@@ -667,31 +709,45 @@ func_body
|
||||
: function_item_list statement
|
||||
{ $$ = new PFunction($1, $2); }
|
||||
| function_item_list
|
||||
{ yyerror(@1, "function body has no statement."); }
|
||||
{ yyerror(@1, "error: function body has no statement.");
|
||||
$$ = new PFunction($1, 0);
|
||||
}
|
||||
;
|
||||
|
||||
/* A function_item is either a block item (i.e. a reg or integer
|
||||
declaration) or an input declaration. There are no output or
|
||||
inout ports. */
|
||||
function_item
|
||||
: K_input range_opt list_of_variables ';'
|
||||
{ svector<PWire*>*tmp
|
||||
= pform_make_task_ports(NetNet::PINPUT, $2, $3);
|
||||
= pform_make_task_ports(NetNet::PINPUT, $2, $3,
|
||||
@1.text, @1.first_line);
|
||||
delete $2;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_reg range_opt list_of_variables ';'
|
||||
{ $$ = 0; }
|
||||
| K_integer list_of_variables ';'
|
||||
| block_item_decl
|
||||
{ $$ = 0; }
|
||||
;
|
||||
|
||||
/* A function_item_list only lists the input/output/inout
|
||||
declarations. The integer and reg declarations are handled in
|
||||
place, so are not listed. The list builder needs to account for
|
||||
the possibility that the various parts may be NULL. */
|
||||
function_item_list
|
||||
: function_item
|
||||
{ $$ = $1; }
|
||||
| function_item_list function_item
|
||||
{ svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
|
||||
delete $1;
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
{ if ($1 && $2) {
|
||||
svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
|
||||
delete $1;
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
} else if ($1) {
|
||||
$$ = $1;
|
||||
} else {
|
||||
$$ = $2;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
@@ -798,19 +854,19 @@ identifier
|
||||
: IDENTIFIER
|
||||
{ $$ = $1; }
|
||||
| HIDENTIFIER
|
||||
{ yyerror(@1, "Sorry, qualified identifiers not supported.");
|
||||
{ yyerror(@1, "sorry: qualified identifiers not supported.");
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
list_of_ports
|
||||
: port
|
||||
: port_opt
|
||||
{ svector<Module::port_t*>*tmp
|
||||
= new svector<Module::port_t*>(1);
|
||||
(*tmp)[0] = $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| list_of_ports ',' port
|
||||
| list_of_ports ',' port_opt
|
||||
{ svector<Module::port_t*>*tmp
|
||||
= new svector<Module::port_t*>(*$1, $3);
|
||||
delete $1;
|
||||
@@ -820,7 +876,6 @@ list_of_ports
|
||||
|
||||
list_of_ports_opt
|
||||
: '(' list_of_ports ')' { $$ = $2; }
|
||||
| '(' ')' { $$ = 0; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
@@ -854,7 +909,7 @@ lavalue
|
||||
{ PEIdent*tmp = new PEIdent($1);
|
||||
PExpr*sel = $3;
|
||||
if (! pform_expression_is_constant(sel)) {
|
||||
yyerror(@2, "Bit select in lvalue must "
|
||||
yyerror(@2, "eror: Bit select in lvalue must "
|
||||
"contain a constant expression.");
|
||||
delete sel;
|
||||
} else {
|
||||
@@ -922,6 +977,26 @@ lpvalue
|
||||
}
|
||||
;
|
||||
|
||||
assign
|
||||
: lavalue '=' expression
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(2);
|
||||
(*tmp)[0] = $1;
|
||||
(*tmp)[1] = $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
assign_list
|
||||
: assign_list ',' assign
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*>(*$1, *$3);
|
||||
delete $1;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| assign
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
module
|
||||
: K_module IDENTIFIER list_of_ports_opt ';'
|
||||
{ pform_startmodule($2, $3);
|
||||
@@ -958,7 +1033,7 @@ module_item
|
||||
delete $3;
|
||||
}
|
||||
| K_trireg charge_strength_opt range_opt delay_opt list_of_variables ';'
|
||||
{ yyerror(@1, "Sorry, trireg nets not supported.");
|
||||
{ yyerror(@1, "sorry: trireg nets not supported.");
|
||||
delete $3;
|
||||
}
|
||||
| port_type range_opt list_of_variables ';'
|
||||
@@ -969,20 +1044,10 @@ module_item
|
||||
}
|
||||
delete $3;
|
||||
}
|
||||
| K_reg range register_variable_list ';'
|
||||
{ pform_set_net_range($3, $2);
|
||||
delete $2;
|
||||
delete $3;
|
||||
}
|
||||
| K_reg register_variable_list ';'
|
||||
{ delete $2; }
|
||||
| K_integer register_variable_list ';'
|
||||
{ pform_set_reg_integer($2);
|
||||
delete $2;
|
||||
}
|
||||
| block_item_decl
|
||||
| K_defparam defparam_assign_list ';'
|
||||
| K_event list_of_variables ';'
|
||||
{ yyerror(@1, "Sorry, named events not supported.");
|
||||
{ yyerror(@1, "sorry: named events not supported.");
|
||||
delete $2;
|
||||
}
|
||||
| K_parameter parameter_assign_list ';'
|
||||
@@ -990,18 +1055,11 @@ module_item
|
||||
{ pform_makegates($1, $2, $3);
|
||||
}
|
||||
| IDENTIFIER delay_opt gate_instance_list ';'
|
||||
{ pform_make_modgates($1, $3);
|
||||
{ pform_make_modgates($1, $2, $3);
|
||||
delete $1;
|
||||
if ($2) {
|
||||
yyerror(@2, "Sorry, parameter override not supported.");
|
||||
delete $2;
|
||||
}
|
||||
}
|
||||
| K_assign delay_opt lavalue '=' expression ';'
|
||||
{ PGAssign*tmp = pform_make_pgassign($3, $5, $2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
}
|
||||
| K_assign delay_opt assign_list ';'
|
||||
{ pform_make_pgassign_list($3, $2, @1.text, @1.first_line); }
|
||||
| K_assign error '=' expression ';'
|
||||
| K_always statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $2);
|
||||
@@ -1032,7 +1090,7 @@ module_item
|
||||
{ PFunction *tmp = $6;
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
pform_set_function($3, $6);
|
||||
pform_set_function($3, $2, $6);
|
||||
delete $3;
|
||||
}
|
||||
| K_specify specify_item_list K_endspecify
|
||||
@@ -1045,7 +1103,7 @@ module_item
|
||||
delete $7;
|
||||
}
|
||||
| KK_attribute '(' error ')' ';'
|
||||
{ yyerror(@1, "Misformed $attribute parameter list."); }
|
||||
{ yyerror(@1, "error: Misformed $attribute parameter list."); }
|
||||
;
|
||||
|
||||
module_item_list
|
||||
@@ -1105,7 +1163,8 @@ parameter_assign
|
||||
: IDENTIFIER '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
if (!pform_expression_is_constant(tmp)) {
|
||||
yyerror(@3, "parameter value must be constant.");
|
||||
yyerror(@3, "error: parameter value "
|
||||
"must be constant.");
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
@@ -1117,7 +1176,7 @@ parameter_assign
|
||||
parameter_assign_list
|
||||
: parameter_assign
|
||||
| range parameter_assign
|
||||
{ yyerror(@1, "Ranges in parameter definition "
|
||||
{ yywarn(@1, "Ranges in parameter definition "
|
||||
"are not supported.");
|
||||
delete $1;
|
||||
}
|
||||
@@ -1159,6 +1218,11 @@ port
|
||||
}
|
||||
;
|
||||
|
||||
port_opt
|
||||
: port { $$ = $1; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
port_reference
|
||||
: IDENTIFIER
|
||||
{ Module::port_t*ptmp = new Module::port_t(1);
|
||||
@@ -1177,11 +1241,11 @@ port_reference
|
||||
wtmp->set_file(@1.text);
|
||||
wtmp->set_lineno(@1.first_line);
|
||||
if (!pform_expression_is_constant($3)) {
|
||||
yyerror(@3, "msb expression of port bit select "
|
||||
yyerror(@3, "error: msb expression of port bit select "
|
||||
"must be constant.");
|
||||
}
|
||||
if (!pform_expression_is_constant($5)) {
|
||||
yyerror(@5, "lsb expression of port bit select "
|
||||
yyerror(@5, "error: lsb expression of port bit select "
|
||||
"must be constant.");
|
||||
}
|
||||
wtmp->set_range($3, $5);
|
||||
@@ -1192,7 +1256,7 @@ port_reference
|
||||
$$ = ptmp;
|
||||
}
|
||||
| IDENTIFIER '[' error ']'
|
||||
{ yyerror(@1, "invalid port bit select");
|
||||
{ yyerror(@1, "error: invalid port bit select");
|
||||
Module::port_t*ptmp = new Module::port_t(1);
|
||||
PWire*wtmp = new PWire($1, NetNet::IMPLICIT,
|
||||
NetNet::PIMPLICIT);
|
||||
@@ -1229,7 +1293,7 @@ port_name
|
||||
$$ = tmp;
|
||||
}
|
||||
| PORTNAME '(' error ')'
|
||||
{ yyerror(@3, "invalid port connection expression.");
|
||||
{ yyerror(@3, "error: invalid port connection expression.");
|
||||
portname_t*tmp = new portname_t;
|
||||
tmp->name = $1;
|
||||
tmp->parm = 0;
|
||||
@@ -1269,12 +1333,12 @@ range
|
||||
: '[' expression ':' expression ']'
|
||||
{ svector<PExpr*>*tmp = new svector<PExpr*> (2);
|
||||
if (!pform_expression_is_constant($2))
|
||||
yyerror(@2, "msb of range must be constant.");
|
||||
yyerror(@2, "error: msb of range must be constant.");
|
||||
|
||||
(*tmp)[0] = $2;
|
||||
|
||||
if (!pform_expression_is_constant($4))
|
||||
yyerror(@4, "msb of range must be constant.");
|
||||
yyerror(@4, "error: msb of range must be constant.");
|
||||
|
||||
(*tmp)[1] = $4;
|
||||
|
||||
@@ -1288,12 +1352,12 @@ range_opt
|
||||
;
|
||||
|
||||
range_or_type_opt
|
||||
: range { }
|
||||
| K_integer
|
||||
| K_real
|
||||
| K_realtime
|
||||
| K_time
|
||||
|
|
||||
: range { $$ = $1; }
|
||||
| K_integer { $$ = 0; }
|
||||
| K_real { $$ = 0; }
|
||||
| K_realtime { $$ = 0; }
|
||||
| K_time { $$ = 0; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
/* The register_variable rule is matched only when I am parsing
|
||||
variables in a "reg" definition. I therefore know that I am
|
||||
@@ -1307,16 +1371,16 @@ register_variable
|
||||
}
|
||||
| IDENTIFIER '=' expression
|
||||
{ pform_makewire(@1, $1, NetNet::REG);
|
||||
yyerror(@2, "net declaration assignment to reg/integer not allowed.");
|
||||
yyerror(@2, "error: net declaration assignment to reg/integer not allowed.");
|
||||
delete $3;
|
||||
$$ = $1;
|
||||
}
|
||||
| IDENTIFIER '[' expression ':' expression ']'
|
||||
{ pform_makewire(@1, $1, NetNet::REG);
|
||||
if (! pform_expression_is_constant($3))
|
||||
yyerror(@3, "msb of register range must be constant.");
|
||||
yyerror(@3, "error: msb of register range must be constant.");
|
||||
if (! pform_expression_is_constant($5))
|
||||
yyerror(@3, "lsb of register range must be constant.");
|
||||
yyerror(@3, "error: lsb of register range must be constant.");
|
||||
pform_set_reg_idx($1, $3, $5);
|
||||
$$ = $1;
|
||||
}
|
||||
@@ -1340,8 +1404,7 @@ register_variable_list
|
||||
specify_item
|
||||
: K_specparam specparam_list ';'
|
||||
| specify_simple_path '=' '(' expression_list ')' ';'
|
||||
{ /* yyerror(@1, "Sorry, specify path declarations not supported."); */
|
||||
delete $4;
|
||||
{ delete $4;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1357,8 +1420,7 @@ specify_simple_path
|
||||
|
||||
specparam
|
||||
: IDENTIFIER '=' expression
|
||||
{ /* yyerror(@1, "Sorry, specparam assignments not supported."); */
|
||||
delete $1;
|
||||
{ delete $1;
|
||||
delete $3;
|
||||
}
|
||||
;
|
||||
@@ -1372,7 +1434,7 @@ spec_polarity: '+' | '-' | ;
|
||||
|
||||
statement
|
||||
: K_assign lavalue '=' expression ';'
|
||||
{ yyerror(@1, "Sorry, procedural continuous assign not supported.");
|
||||
{ yyerror(@1, "sorry: procedural continuous assign not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_begin statement_list K_end
|
||||
@@ -1409,16 +1471,16 @@ statement
|
||||
| K_begin error K_end
|
||||
{ yyerrok; }
|
||||
| K_deassign lavalue';'
|
||||
{ yyerror(@1, "Sorry, deassign not supported.");
|
||||
{ yyerror(@1, "sorry:, deassign not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_disable IDENTIFIER ';'
|
||||
{ yyerror(@1, "Sorry, disable statements not supported.");
|
||||
{ yyerror(@1, "sorry: disable statements not supported.");
|
||||
delete $2;
|
||||
$$ = 0;
|
||||
}
|
||||
| K_force lavalue '=' expression ';'
|
||||
{ yyerror(@1, "Sorry, procedural force assign not supported.");
|
||||
{ yyerror(@1, "sorry: procedural force assign not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_forever statement
|
||||
@@ -1434,14 +1496,16 @@ statement
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_release lavalue ';'
|
||||
{ yyerror(@1, "Sorry, release not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_repeat '(' expression ')' statement
|
||||
{ PRepeat*tmp = new PRepeat($3, $5);
|
||||
| K_fork ':' IDENTIFIER
|
||||
{ pform_push_scope($3); }
|
||||
block_item_decls_opt
|
||||
statement_list K_join
|
||||
{ pform_pop_scope();
|
||||
PBlock*tmp = new PBlock($3, PBlock::BL_PAR, *$6);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
delete $3;
|
||||
delete $6;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_fork K_join
|
||||
@@ -1450,24 +1514,38 @@ statement
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_fork ':' IDENTIFIER K_join
|
||||
{ PBlock*tmp = new PBlock(PBlock::BL_PAR);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_release lavalue ';'
|
||||
{ yyerror(@1, "sorry: release not supported.");
|
||||
$$ = 0;
|
||||
}
|
||||
| K_repeat '(' expression ')' statement
|
||||
{ PRepeat*tmp = new PRepeat($3, $5);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_case '(' expression ')' case_items K_endcase
|
||||
{ PCase*tmp = new PCase($3, $5);
|
||||
{ PCase*tmp = new PCase(NetCase::EQ, $3, $5);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_casex '(' expression ')' case_items K_endcase
|
||||
{ PCase*tmp = new PCase($3, $5);
|
||||
{ PCase*tmp = new PCase(NetCase::EQX, $3, $5);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
yywarn(@1, "casex not properly supported, using case.");
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_casez '(' expression ')' case_items K_endcase
|
||||
{ PCase*tmp = new PCase($3, $5);
|
||||
{ PCase*tmp = new PCase(NetCase::EQZ, $3, $5);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
yywarn(@1, "casez not properly supported, using case.");
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_case '(' expression ')' error K_endcase
|
||||
@@ -1476,7 +1554,7 @@ statement
|
||||
{ yyerrok; }
|
||||
| K_casez '(' expression ')' error K_endcase
|
||||
{ yyerrok; }
|
||||
| K_if '(' expression ')' statement_opt
|
||||
| K_if '(' expression ')' statement_opt %prec less_than_K_else
|
||||
{ PCondit*tmp = new PCondit($3, $5, 0);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
@@ -1488,12 +1566,12 @@ statement
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_if '(' error ')' statement_opt
|
||||
{ yyerror(@1, "Malformed conditional expression.");
|
||||
| K_if '(' error ')' statement_opt %prec less_than_K_else
|
||||
{ yyerror(@1, "error: Malformed conditional expression.");
|
||||
$$ = $5;
|
||||
}
|
||||
| K_if '(' error ')' statement_opt K_else statement_opt
|
||||
{ yyerror(@1, "Malformed conditional expression.");
|
||||
{ yyerror(@1, "error: Malformed conditional expression.");
|
||||
$$ = $5;
|
||||
}
|
||||
| K_for '(' lpvalue '=' expression ';' expression ';'
|
||||
@@ -1506,16 +1584,16 @@ statement
|
||||
| K_for '(' lpvalue '=' expression ';' expression ';'
|
||||
error ')' statement
|
||||
{ $$ = 0;
|
||||
yyerror(@9, "Error in for loop step assigment.");
|
||||
yyerror(@9, "error: Error in for loop step assigment.");
|
||||
}
|
||||
| K_for '(' lpvalue '=' expression ';' error ';'
|
||||
lpvalue '=' expression ')' statement
|
||||
{ $$ = 0;
|
||||
yyerror(@7, "Error in for loop condition expression.");
|
||||
yyerror(@7, "error: Error in for loop condition expression.");
|
||||
}
|
||||
| K_for '(' error ')' statement
|
||||
{ $$ = 0;
|
||||
yyerror(@3, "Incomprehensible for loop.");
|
||||
yyerror(@3, "error: Incomprehensible for loop.");
|
||||
}
|
||||
| K_while '(' expression ')' statement
|
||||
{ PWhile*tmp = new PWhile($3, $5);
|
||||
@@ -1523,12 +1601,12 @@ statement
|
||||
}
|
||||
| K_while '(' error ')' statement
|
||||
{ $$ = 0;
|
||||
yyerror(@3, "Error in while loop condition.");
|
||||
yyerror(@3, "error: Error in while loop condition.");
|
||||
}
|
||||
| delay statement_opt
|
||||
{ PExpr*del = (*$1)[0];
|
||||
if ($1->count() != 1)
|
||||
yyerror(@1, "Sorry, delay lists not supported here.");
|
||||
yyerror(@1, "sorry: delay lists not supported here.");
|
||||
PDelayStatement*tmp = new PDelayStatement(del, $2);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
@@ -1537,7 +1615,7 @@ statement
|
||||
| event_control statement_opt
|
||||
{ PEventStatement*tmp = $1;
|
||||
if (tmp == 0) {
|
||||
yyerror(@1, "Invalid event control.");
|
||||
yyerror(@1, "error: Invalid event control.");
|
||||
$$ = 0;
|
||||
} else {
|
||||
tmp->set_statement($2);
|
||||
@@ -1559,12 +1637,34 @@ statement
|
||||
| lpvalue '=' delay expression ';'
|
||||
{ PExpr*del = (*$3)[0];
|
||||
if ($3->count() != 1)
|
||||
yyerror(@1, "Sorry, delay lists not supported here.");
|
||||
yyerror(@1, "sorry: Delay lists not supported here.");
|
||||
PAssign*tmp = new PAssign($1,del,$4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue K_LE delay expression ';'
|
||||
{ PExpr*del = (*$3)[0];
|
||||
if ($3->count() != 1)
|
||||
yyerror(@1, "sorry: Delay lists not supported here.");
|
||||
PAssignNB*tmp = new PAssignNB($1,del,$4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue '=' event_control expression ';'
|
||||
{ PAssign*tmp = new PAssign($1,$3,$4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| lpvalue K_LE event_control expression ';'
|
||||
{ yyerror(@1, "sorry: Event controls not supported here.");
|
||||
PAssignNB*tmp = new PAssignNB($1,$4);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_wait '(' expression ')' statement_opt
|
||||
{ PEventStatement*tmp;
|
||||
PEEvent*etmp = new PEEvent(NetNEvent::POSITIVE, $3);
|
||||
@@ -1621,7 +1721,7 @@ statement
|
||||
$$ = tmp;
|
||||
}
|
||||
| error ';'
|
||||
{ yyerror(@1, "malformed statement");
|
||||
{ yyerror(@1, "error: malformed statement");
|
||||
yyerrok;
|
||||
$$ = new PNoop;
|
||||
}
|
||||
@@ -1654,24 +1754,27 @@ task_body
|
||||
|
||||
task_item
|
||||
: block_item_decl
|
||||
{ $$ = 0; }
|
||||
{ $$ = new svector<PWire*>(0); }
|
||||
| K_input range_opt list_of_variables ';'
|
||||
{ svector<PWire*>*tmp
|
||||
= pform_make_task_ports(NetNet::PINPUT, $2, $3);
|
||||
= pform_make_task_ports(NetNet::PINPUT, $2,
|
||||
$3, @1.text, @1.first_line);
|
||||
delete $2;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_output range_opt list_of_variables ';'
|
||||
{ svector<PWire*>*tmp
|
||||
= pform_make_task_ports(NetNet::POUTPUT, $2, $3);
|
||||
= pform_make_task_ports(NetNet::POUTPUT, $2, $3,
|
||||
@1.text, @1.first_line);
|
||||
delete $2;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_inout range_opt list_of_variables ';'
|
||||
{ svector<PWire*>*tmp
|
||||
= pform_make_task_ports(NetNet::PINOUT, $2, $3);
|
||||
= pform_make_task_ports(NetNet::PINOUT, $2, $3,
|
||||
@1.text, @1.first_line);
|
||||
delete $2;
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
|
||||
+5
-2
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: parse_misc.cc,v 1.2 1998/11/07 17:05:05 steve Exp $"
|
||||
#ident "$Id: parse_misc.cc,v 1.3 1999/09/29 21:15:31 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "parse_misc.h"
|
||||
@@ -48,7 +48,7 @@ void yywarn(const YYLTYPE&loc, const char*msg)
|
||||
if (loc.text)
|
||||
cerr << loc.text << ":";
|
||||
|
||||
cerr << loc.first_line << ": warning -- " << msg << endl;
|
||||
cerr << loc.first_line << ": warning: " << msg << endl;
|
||||
}
|
||||
|
||||
int VLwrap()
|
||||
@@ -58,6 +58,9 @@ int VLwrap()
|
||||
|
||||
/*
|
||||
* $Log: parse_misc.cc,v $
|
||||
* Revision 1.3 1999/09/29 21:15:31 steve
|
||||
* Standardize formatting of warning messages.
|
||||
*
|
||||
* Revision 1.2 1998/11/07 17:05:05 steve
|
||||
* Handle procedural conditional, and some
|
||||
* of the conditional expressions.
|
||||
|
||||
@@ -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.37 1999/08/03 04:14:49 steve Exp $"
|
||||
#ident "$Id: pform.cc,v 1.46 1999/09/30 01:22:37 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "compiler.h"
|
||||
@@ -42,7 +42,9 @@ static Module*pform_cur_module = 0;
|
||||
/*
|
||||
* The scope stack and the following functions handle the processing
|
||||
* of scope. As I enter a scope, the push function is called, and as I
|
||||
* leave a scope the opo function is called.
|
||||
* leave a scope the pop function is called.
|
||||
*
|
||||
* The top module is not included in the scope list.
|
||||
*/
|
||||
struct scope_name_t {
|
||||
string name;
|
||||
@@ -97,6 +99,15 @@ static unsigned long evaluate_delay(PExpr*delay)
|
||||
void pform_startmodule(const string&name, svector<Module::port_t*>*ports)
|
||||
{
|
||||
assert( pform_cur_module == 0 );
|
||||
|
||||
/* The parser parses ``module foo()'' as having one
|
||||
unconnected port, but it is really a module with no
|
||||
ports. Fix it up here. */
|
||||
if (ports && (ports->count() == 1) && ((*ports)[0] == 0)) {
|
||||
delete ports;
|
||||
ports = 0;
|
||||
}
|
||||
|
||||
pform_cur_module = new Module(name, ports);
|
||||
delete ports;
|
||||
}
|
||||
@@ -296,6 +307,7 @@ void pform_makegates(PGBuiltin::Type type,
|
||||
*/
|
||||
static void pform_make_modgate(const string&type,
|
||||
const string&name,
|
||||
svector<PExpr*>*overrides,
|
||||
svector<PExpr*>*wires,
|
||||
const string&fn, unsigned ln)
|
||||
{
|
||||
@@ -306,7 +318,7 @@ static void pform_make_modgate(const string&type,
|
||||
return;
|
||||
}
|
||||
|
||||
PGate*cur = new PGModule(type, name, wires);
|
||||
PGate*cur = new PGModule(type, name, overrides, wires);
|
||||
cur->set_file(fn);
|
||||
cur->set_lineno(ln);
|
||||
pform_cur_module->add_gate(cur);
|
||||
@@ -314,6 +326,7 @@ static void pform_make_modgate(const string&type,
|
||||
|
||||
static void pform_make_modgate(const string&type,
|
||||
const string&name,
|
||||
svector<PExpr*>*overrides,
|
||||
svector<portname_t*>*bind,
|
||||
const string&fn, unsigned ln)
|
||||
{
|
||||
@@ -332,27 +345,29 @@ static void pform_make_modgate(const string&type,
|
||||
pins[idx].parm = curp->parm;
|
||||
}
|
||||
|
||||
PGate*cur = new PGModule(type, name, pins, npins);
|
||||
PGate*cur = new PGModule(type, name, overrides, pins, npins);
|
||||
cur->set_file(fn);
|
||||
cur->set_lineno(ln);
|
||||
pform_cur_module->add_gate(cur);
|
||||
}
|
||||
|
||||
void pform_make_modgates(const string&type, svector<lgate>*gates)
|
||||
void pform_make_modgates(const string&type,
|
||||
svector<PExpr*>*overrides,
|
||||
svector<lgate>*gates)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
|
||||
lgate cur = (*gates)[idx];
|
||||
|
||||
if (cur.parms_by_name) {
|
||||
pform_make_modgate(type, cur.name, cur.parms_by_name,
|
||||
pform_make_modgate(type, cur.name, overrides, cur.parms_by_name,
|
||||
cur.file, cur.lineno);
|
||||
|
||||
} else if (cur.parms) {
|
||||
pform_make_modgate(type, cur.name, cur.parms, cur.file,
|
||||
pform_make_modgate(type, cur.name, overrides, cur.parms, cur.file,
|
||||
cur.lineno);
|
||||
} else {
|
||||
svector<PExpr*>*wires = new svector<PExpr*>(0);
|
||||
pform_make_modgate(type, cur.name, wires, cur.file,
|
||||
pform_make_modgate(type, cur.name, overrides, wires, cur.file,
|
||||
cur.lineno);
|
||||
}
|
||||
}
|
||||
@@ -378,6 +393,20 @@ PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
|
||||
return cur;
|
||||
}
|
||||
|
||||
void pform_make_pgassign_list(svector<PExpr*>*alist,
|
||||
svector<PExpr*>*del,
|
||||
const string& text,
|
||||
unsigned lineno)
|
||||
{
|
||||
PGAssign*tmp;
|
||||
for (unsigned idx = 0 ; idx < alist->count()/2 ; idx += 1) {
|
||||
tmp = pform_make_pgassign((*alist)[2*idx],
|
||||
(*alist)[2*idx+1], del);
|
||||
tmp->set_file(text);
|
||||
tmp->set_lineno(lineno);
|
||||
}
|
||||
}
|
||||
|
||||
void pform_makewire(const vlltype&li, const string&nm,
|
||||
NetNet::Type type)
|
||||
{
|
||||
@@ -465,8 +494,11 @@ void pform_set_port_type(const string&name, NetNet::PortType pt)
|
||||
*/
|
||||
svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
|
||||
const svector<PExpr*>*range,
|
||||
const list<string>*names)
|
||||
const list<string>*names,
|
||||
const string& file,
|
||||
unsigned lineno)
|
||||
{
|
||||
assert(names);
|
||||
svector<PWire*>*res = new svector<PWire*>(0);
|
||||
for (list<string>::const_iterator cur = names->begin()
|
||||
; cur != names->end() ; cur ++ ) {
|
||||
@@ -480,6 +512,8 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
|
||||
curw->set_port_type(pt);
|
||||
} else {
|
||||
curw = new PWire(name, NetNet::IMPLICIT_REG, pt);
|
||||
curw->set_file(file);
|
||||
curw->set_lineno(lineno);
|
||||
pform_cur_module->add_wire(curw);
|
||||
}
|
||||
|
||||
@@ -500,8 +534,21 @@ void pform_set_task(const string&name, PTask*task)
|
||||
pform_cur_module->add_task(name, task);
|
||||
}
|
||||
|
||||
void pform_set_function(const string&name, PFunction *func)
|
||||
/*
|
||||
* This function is called to fill out the definition of the function
|
||||
* with the trappings that are discovered after the basic function
|
||||
* name is parsed.
|
||||
*/
|
||||
void pform_set_function(const string&name, svector<PExpr*>*ra, PFunction *func)
|
||||
{
|
||||
PWire*out = new PWire(name+"."+name, NetNet::REG, NetNet::POUTPUT);
|
||||
if (ra) {
|
||||
assert(ra->count() == 2);
|
||||
out->set_range((*ra)[0], (*ra)[1]);
|
||||
delete ra;
|
||||
}
|
||||
pform_cur_module->add_wire(out);
|
||||
func->set_output(out);
|
||||
pform_cur_module->add_function(name, func);
|
||||
}
|
||||
|
||||
@@ -536,21 +583,26 @@ void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r)
|
||||
{
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
if (cur == 0) {
|
||||
VLerror("name is not a valid net.");
|
||||
VLerror(" error: name is not a valid net.");
|
||||
return;
|
||||
}
|
||||
|
||||
cur->set_memory_idx(l, r);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function attaches a range to a given name. The function is
|
||||
* only called by the parser within the scope of the net declaration,
|
||||
* and the name that I receive only has the tail component.
|
||||
*/
|
||||
static void pform_set_net_range(const string&name, const svector<PExpr*>*range)
|
||||
{
|
||||
assert(range);
|
||||
assert(range->count() == 2);
|
||||
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
PWire*cur = pform_cur_module->get_wire(scoped_name(name));
|
||||
if (cur == 0) {
|
||||
VLerror("name is not a valid net.");
|
||||
VLerror(" error: name is not a valid net.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -573,6 +625,7 @@ void pform_set_net_range(list<string>*names, const svector<PExpr*>*range)
|
||||
void pform_set_parameter(const string&name, PExpr*expr)
|
||||
{
|
||||
pform_cur_module->parameters[name] = expr;
|
||||
pform_cur_module->param_names.push_back(name);
|
||||
}
|
||||
|
||||
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
|
||||
@@ -584,12 +637,18 @@ void pform_set_port_type(list<string>*names, NetNet::PortType pt)
|
||||
}
|
||||
}
|
||||
|
||||
static void pform_set_reg_integer(const string&name)
|
||||
static void pform_set_reg_integer(const string&nm)
|
||||
{
|
||||
string name = scoped_name(nm);
|
||||
PWire*cur = pform_cur_module->get_wire(name);
|
||||
if (cur == 0) {
|
||||
cur = new PWire(name, NetNet::INTEGER, NetNet::NOT_A_PORT);
|
||||
pform_cur_module->add_wire(cur);
|
||||
} else {
|
||||
bool rc = cur->set_wire_type(NetNet::INTEGER);
|
||||
assert(rc);
|
||||
}
|
||||
assert(cur);
|
||||
bool rc = cur->set_wire_type(NetNet::INTEGER);
|
||||
assert(rc);
|
||||
|
||||
cur->set_range(new PENumber(new verinum(INTEGER_WIDTH-1, INTEGER_WIDTH)),
|
||||
new PENumber(new verinum(0UL, INTEGER_WIDTH)));
|
||||
@@ -655,6 +714,34 @@ int pform_parse(const char*path, map<string,Module*>&modules,
|
||||
|
||||
/*
|
||||
* $Log: pform.cc,v $
|
||||
* Revision 1.46 1999/09/30 01:22:37 steve
|
||||
* Handle declaration of integers (including scope) in functions.
|
||||
*
|
||||
* Revision 1.45 1999/09/21 00:58:33 steve
|
||||
* Get scope right when setting the net range.
|
||||
*
|
||||
* Revision 1.44 1999/09/17 02:06:26 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
* Revision 1.43 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.42 1999/09/10 05:02:09 steve
|
||||
* Handle integers at task parameters.
|
||||
*
|
||||
* Revision 1.41 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.40 1999/08/27 15:08:37 steve
|
||||
* continuous assignment lists.
|
||||
*
|
||||
* Revision 1.39 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.38 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.37 1999/08/03 04:14:49 steve
|
||||
* Parse into pform arbitrarily complex module
|
||||
* port declarations.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: pform.h,v 1.27 1999/08/03 04:14:49 steve Exp $"
|
||||
#ident "$Id: pform.h,v 1.31 1999/09/10 05:02:09 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -121,7 +121,7 @@ extern void pform_set_net_range(list<string>*names, const svector<PExpr*>*);
|
||||
extern void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r);
|
||||
extern void pform_set_reg_integer(list<string>*names);
|
||||
extern void pform_set_task(const string&, PTask*);
|
||||
extern void pform_set_function(const string&, PFunction*);
|
||||
extern void pform_set_function(const string&, svector<PExpr*>*, PFunction*);
|
||||
extern void pform_set_attrib(const string&name, const string&key,
|
||||
const string&value);
|
||||
extern void pform_set_type_attrib(const string&name, const string&key,
|
||||
@@ -141,18 +141,25 @@ extern void pform_makegates(PGBuiltin::Type type,
|
||||
svector<PExpr*>*delay,
|
||||
svector<lgate>*gates);
|
||||
|
||||
extern void pform_make_modgates(const string&type, svector<lgate>*gates);
|
||||
extern void pform_make_modgates(const string&type,
|
||||
svector<PExpr*>*overrides,
|
||||
svector<lgate>*gates);
|
||||
|
||||
/* Make a continuous assignment node, with optional bit- or part- select. */
|
||||
extern PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
|
||||
svector<PExpr*>*delays);
|
||||
|
||||
extern void pform_make_pgassign_list(svector<PExpr*>*alist,
|
||||
svector<PExpr*>*del,
|
||||
const string& text,
|
||||
unsigned lineno);
|
||||
|
||||
/* Given a port type and a list of names, make a list of wires that
|
||||
can be used as task port information. */
|
||||
extern svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
|
||||
const svector<PExpr*>*range,
|
||||
const list<string>*names);
|
||||
const list<string>*names,
|
||||
const string& file,
|
||||
unsigned lineno);
|
||||
|
||||
|
||||
/*
|
||||
@@ -167,6 +174,19 @@ extern void pform_dump(ostream&out, Module*mod);
|
||||
|
||||
/*
|
||||
* $Log: pform.h,v $
|
||||
* Revision 1.31 1999/09/10 05:02:09 steve
|
||||
* Handle integers at task parameters.
|
||||
*
|
||||
* Revision 1.30 1999/08/27 15:08:37 steve
|
||||
* continuous assignment lists.
|
||||
*
|
||||
* Revision 1.29 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.28 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.27 1999/08/03 04:14:49 steve
|
||||
* Parse into pform arbitrarily complex module
|
||||
* port declarations.
|
||||
|
||||
+106
-22
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: pform_dump.cc,v 1.34 1999/08/03 04:49:13 steve Exp $"
|
||||
#ident "$Id: pform_dump.cc,v 1.44 1999/09/30 02:43:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -37,6 +37,12 @@ ostream& operator << (ostream&out, const PExpr&obj)
|
||||
return out;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream&o, const PDelays&d)
|
||||
{
|
||||
d.dump_delays(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
void PExpr::dump(ostream&out) const
|
||||
{
|
||||
out << typeid(*this).name();
|
||||
@@ -65,7 +71,7 @@ void PECallFunction::dump(ostream &out) const
|
||||
{
|
||||
out << name_ << "(";
|
||||
parms_[0]->dump(out);
|
||||
for (unsigned idx = 0; idx < parms_.count(); ++idx) {
|
||||
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
|
||||
out << ", ";
|
||||
parms_[idx]->dump(out);
|
||||
}
|
||||
@@ -209,7 +215,7 @@ void PGate::dump_pins(ostream&out) const
|
||||
}
|
||||
}
|
||||
|
||||
void PGate::dump_delays(ostream&out) const
|
||||
void PDelays::dump_delays(ostream&out) const
|
||||
{
|
||||
if (delay_[0] && delay_[1] && delay_[2])
|
||||
out << "#(" << *delay_[0] << "," << *delay_[1] << "," <<
|
||||
@@ -221,10 +227,15 @@ void PGate::dump_delays(ostream&out) const
|
||||
|
||||
}
|
||||
|
||||
void PGate::dump_delays(ostream&out) const
|
||||
{
|
||||
delay_.dump_delays(out);
|
||||
}
|
||||
|
||||
void PGate::dump(ostream&out) const
|
||||
{
|
||||
out << " " << typeid(*this).name() << " ";
|
||||
dump_delays(out);
|
||||
delay_.dump_delays(out);
|
||||
out << " " << get_name() << "(";
|
||||
dump_pins(out);
|
||||
out << ");" << endl;
|
||||
@@ -268,12 +279,25 @@ void PGBuiltin::dump(ostream&out) const
|
||||
|
||||
void PGModule::dump(ostream&out) const
|
||||
{
|
||||
out << " " << type_ << " " << get_name() << "(";
|
||||
out << " " << type_ << " ";
|
||||
if (overrides_) {
|
||||
out << "#(";
|
||||
out << *((*overrides_)[0]);
|
||||
for (unsigned idx = 1 ; idx < overrides_->count() ; idx += 1) {
|
||||
out << "," << *((*overrides_)[idx]);
|
||||
}
|
||||
out << ") ";
|
||||
}
|
||||
out << get_name() << "(";
|
||||
if (pins_) {
|
||||
out << "." << pins_[0].name << "(" << *pins_[0].parm << ")";
|
||||
out << "." << pins_[0].name << "(";
|
||||
if (pins_[0].parm) out << *pins_[0].parm;
|
||||
out << ")";
|
||||
for (unsigned idx = 1 ; idx < npins_ ; idx += 1) {
|
||||
out << ", ." << pins_[idx].name << "(" <<
|
||||
*pins_[idx].parm << ")";
|
||||
out << ", ." << pins_[idx].name << "(";
|
||||
if (pins_[idx].parm)
|
||||
out << *pins_[idx].parm;
|
||||
out << ")";
|
||||
}
|
||||
} else {
|
||||
dump_pins(out);
|
||||
@@ -294,18 +318,14 @@ void Statement::dump(ostream&out, unsigned ind) const
|
||||
void PAssign::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "";
|
||||
out << *lval() << " = ";
|
||||
if (delay()) out << "#" << *delay() << " ";
|
||||
out << *rval() << ";";
|
||||
out << *lval() << " = " << delay_ << " " << *rval() << ";";
|
||||
out << " /* " << get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
void PAssignNB::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "";
|
||||
out << *lval() << " <= ";
|
||||
if (delay()) out << "#" << *delay() << " ";
|
||||
out << *rval() << ";";
|
||||
out << *lval() << " <= " << delay_ << " " << *rval() << ";";
|
||||
out << " /* " << get_line() << " */" << endl;
|
||||
}
|
||||
|
||||
@@ -317,7 +337,10 @@ void PBlock::dump(ostream&out, unsigned ind) const
|
||||
out << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) {
|
||||
list_[idx]->dump(out, ind+2);
|
||||
if (list_[idx])
|
||||
list_[idx]->dump(out, ind+2);
|
||||
else
|
||||
out << setw(ind+2) << "" << "/* NOOP */ ;" << endl;
|
||||
}
|
||||
|
||||
out << setw(ind) << "" << "end" << endl;
|
||||
@@ -345,8 +368,19 @@ void PCallTask::dump(ostream&out, unsigned ind) const
|
||||
|
||||
void PCase::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "case (" << *expr_ << ") /* " <<
|
||||
get_line() << " */" << endl;
|
||||
out << setw(ind) << "";
|
||||
switch (type_) {
|
||||
case NetCase::EQ:
|
||||
out << "case";
|
||||
break;
|
||||
case NetCase::EQX:
|
||||
out << "casex";
|
||||
break;
|
||||
case NetCase::EQZ:
|
||||
out << "casez";
|
||||
break;
|
||||
}
|
||||
out << " (" << *expr_ << ") /* " << get_line() << " */" << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
|
||||
PCase::Item*cur = (*items_)[idx];
|
||||
@@ -377,7 +411,10 @@ void PCase::dump(ostream&out, unsigned ind) const
|
||||
void PCondit::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "if (" << *expr_ << ")" << endl;
|
||||
if_->dump(out, ind+3);
|
||||
if (if_)
|
||||
if_->dump(out, ind+3);
|
||||
else
|
||||
out << setw(ind) << ";" << endl;
|
||||
if (else_) {
|
||||
out << setw(ind) << "" << "else" << endl;
|
||||
else_->dump(out, ind+3);
|
||||
@@ -430,13 +467,17 @@ void PForStatement::dump(ostream&out, unsigned ind) const
|
||||
|
||||
void PFunction::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "output " << out_->name() << ";" << endl;
|
||||
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
|
||||
out << setw(ind) << "";
|
||||
out << "input ";
|
||||
out << (*ports_)[idx]->name() << ";" << endl;
|
||||
}
|
||||
|
||||
statement_->dump(out, ind);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind);
|
||||
else
|
||||
out << setw(ind) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
void PRepeat::dump(ostream&out, unsigned ind) const
|
||||
@@ -464,7 +505,10 @@ void PTask::dump(ostream&out, unsigned ind) const
|
||||
out << (*ports_)[idx]->name() << ";" << endl;
|
||||
}
|
||||
|
||||
statement_->dump(out, ind);
|
||||
if (statement_)
|
||||
statement_->dump(out, ind);
|
||||
else
|
||||
out << setw(ind) << "" << "/* NOOP */" << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -496,6 +540,12 @@ void Module::dump(ostream&out) const
|
||||
|
||||
for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) {
|
||||
port_t*cur = ports_[idx];
|
||||
|
||||
if (cur == 0) {
|
||||
out << " unconnected" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (cur->wires[0]->get_port_type()) {
|
||||
case NetNet::PINPUT:
|
||||
out << " input ." << cur->name << "(";
|
||||
@@ -522,8 +572,11 @@ void Module::dump(ostream&out) const
|
||||
typedef map<string,PExpr*>::const_iterator parm_iter_t;
|
||||
for (parm_iter_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
out << " parameter " << (*cur).first << " = " <<
|
||||
*(*cur).second << ";" << endl;
|
||||
out << " parameter " << (*cur).first << " = ";
|
||||
if ((*cur).second)
|
||||
out << *(*cur).second << ";" << endl;
|
||||
else
|
||||
out << "/* ERROR */;" << endl;
|
||||
}
|
||||
|
||||
// Iterate through and display all the wires.
|
||||
@@ -619,6 +672,37 @@ void PUdp::dump(ostream&out) const
|
||||
|
||||
/*
|
||||
* $Log: pform_dump.cc,v $
|
||||
* Revision 1.44 1999/09/30 02:43:02 steve
|
||||
* Elaborate ~^ and ~| operators.
|
||||
*
|
||||
* Revision 1.43 1999/09/30 00:48:50 steve
|
||||
* Cope with errors during ternary operator elaboration.
|
||||
*
|
||||
* Revision 1.42 1999/09/29 21:15:58 steve
|
||||
* Handle some mor missing names.
|
||||
*
|
||||
* Revision 1.41 1999/09/29 20:23:53 steve
|
||||
* Handle empty named ports in the dump.
|
||||
*
|
||||
* Revision 1.40 1999/09/29 18:36:04 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.39 1999/09/17 02:06:26 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
* Revision 1.38 1999/09/08 02:24:39 steve
|
||||
* Empty conditionals (pmonta@imedia.com)
|
||||
*
|
||||
* Revision 1.37 1999/09/04 19:11:46 steve
|
||||
* Add support for delayed non-blocking assignments.
|
||||
*
|
||||
* Revision 1.36 1999/08/25 22:22:41 steve
|
||||
* elaborate some aspects of functions.
|
||||
*
|
||||
* Revision 1.35 1999/08/23 16:48:39 steve
|
||||
* Parameter overrides support from Peter Monta
|
||||
* AND and XOR support wide expressions.
|
||||
*
|
||||
* Revision 1.34 1999/08/03 04:49:13 steve
|
||||
* Proper port type names.
|
||||
*
|
||||
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* 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: set_width.cc,v 1.6 1999/10/05 06:19:46 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file contains set_width methods for the various NetExpr
|
||||
* classes. The set_width method is used by elaboration to ask the
|
||||
* expression to resize itself. If the expression can't, then the
|
||||
* set_width method will return false and the caller will arrange for
|
||||
* whatever is needed to deal with the size mismatch.
|
||||
*/
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include <typeinfo>
|
||||
|
||||
|
||||
bool NetExpr::set_width(unsigned w)
|
||||
{
|
||||
cerr << typeid(*this).name() << ": set_width(unsigned) "
|
||||
"not implemented." << endl;
|
||||
expr_width(w);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetEBinary::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
switch (op_) {
|
||||
|
||||
case 'l': // left shift (<<)
|
||||
case 'r': // right shift (>>)
|
||||
flag = left_->set_width(w);
|
||||
expr_width(w);
|
||||
break;
|
||||
|
||||
/* The default rule is that the operands of the binary
|
||||
operator might as well use the same width as the
|
||||
output from the binary operation. */
|
||||
default:
|
||||
expr_width(left_->expr_width() > right_->expr_width()
|
||||
? left_->expr_width() : right_->expr_width());
|
||||
cerr << "NetEBinary::set_width(): Using default for " <<
|
||||
op_ << "." << endl;
|
||||
flag = false;
|
||||
|
||||
case '%':
|
||||
case '/':
|
||||
flag = left_->set_width(w) && flag;
|
||||
flag = right_->set_width(w) && flag;
|
||||
expr_width(w);
|
||||
break;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitwise logical operators have operands the same size as the
|
||||
* result. Anything else is a mess.
|
||||
*/
|
||||
bool NetEBAdd::set_width(unsigned w)
|
||||
{
|
||||
|
||||
unsigned wid = w;
|
||||
if (left_->expr_width() > wid)
|
||||
wid = left_->expr_width();
|
||||
if (right_->expr_width() > wid)
|
||||
wid = right_->expr_width();
|
||||
|
||||
left_->set_width(wid);
|
||||
right_->set_width(wid);
|
||||
|
||||
if (left_->expr_width() < wid) {
|
||||
NetExpr*tmp = pad_to_width(left_, wid);
|
||||
assert(tmp);
|
||||
left_ = tmp;
|
||||
}
|
||||
|
||||
if (right_->expr_width() < wid) {
|
||||
NetExpr*tmp = pad_to_width(right_, wid);
|
||||
assert(tmp);
|
||||
right_ = tmp;
|
||||
}
|
||||
|
||||
expr_width(wid);
|
||||
return wid == w;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitwise logical operators have operands the same size as the
|
||||
* result. Anything else is a mess.
|
||||
*/
|
||||
bool NetEBBits::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
flag = left_->set_width(w) && flag;
|
||||
flag = right_->set_width(w) && flag;
|
||||
if (flag)
|
||||
expr_width(w);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparison operators allow the subexpressions to have
|
||||
* their own natural width, but the comparison operator result has a
|
||||
* fixed width of 1.
|
||||
*/
|
||||
bool NetEBComp::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
return (w == 1);
|
||||
}
|
||||
|
||||
bool NetEBLogic::set_width(unsigned w)
|
||||
{
|
||||
bool flag;
|
||||
flag = left_->set_width(right_->expr_width());
|
||||
if (!flag)
|
||||
flag = right_->set_width(left_->expr_width());
|
||||
return (w == 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The shift operator allows the shift amount to have its own
|
||||
* natural width. The width of the operator result is the width of the
|
||||
* left operand, the value that is to be shifted.
|
||||
*/
|
||||
bool NetEBShift::set_width(unsigned w)
|
||||
{
|
||||
bool flag;
|
||||
flag = left_->set_width(w);
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add up the widths from all the expressions that are concatenated
|
||||
* together. This is the width of the expression, tough luck if you
|
||||
* want it otherwise.
|
||||
*
|
||||
* If during the course of elaboration one of the sub-expressions is
|
||||
* broken, then don't count it in the width. This doesn't really
|
||||
* matter because the null expression is indication of an error and
|
||||
* the compiler will not go beyond elaboration.
|
||||
*/
|
||||
bool NetEConcat::set_width(unsigned w)
|
||||
{
|
||||
unsigned sum = 0;
|
||||
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
|
||||
if (parms_[idx] != 0)
|
||||
sum += parms_[idx]->expr_width();
|
||||
|
||||
sum *= repeat_;
|
||||
expr_width(sum);
|
||||
if (sum != w) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEConst::set_width(unsigned w)
|
||||
{
|
||||
if (w > value_.len())
|
||||
return false;
|
||||
|
||||
assert(w <= value_.len());
|
||||
value_ = verinum(value_, w);
|
||||
expr_width(w);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEMemory::set_width(unsigned w)
|
||||
{
|
||||
if (w != mem_->width())
|
||||
return false;
|
||||
|
||||
expr_width(w);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEParam::set_width(unsigned)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The signal should automatically pad with zeros to get to th desired
|
||||
* width. Do not allow signal bits to be truncated, however.
|
||||
*/
|
||||
bool NetESignal::set_width(unsigned w)
|
||||
{
|
||||
if (w != pin_count())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetESubSignal::set_width(unsigned w)
|
||||
{
|
||||
if (w != 1) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetETernary::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
flag = flag && true_val_->set_width(w);
|
||||
flag = flag && false_val_->set_width(w);
|
||||
expr_width(true_val_->expr_width());
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXX FIX ME: For now, just take whatever the caller says as my
|
||||
* width. What I really need to do is note the width of the output
|
||||
* parameter of the function definition and take that into account.
|
||||
*/
|
||||
bool NetEUFunc::set_width(unsigned wid)
|
||||
{
|
||||
expr_width(wid);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetEUnary::set_width(unsigned w)
|
||||
{
|
||||
bool flag = true;
|
||||
switch (op_) {
|
||||
case '~':
|
||||
case '-':
|
||||
flag = expr_->set_width(w);
|
||||
break;
|
||||
default:
|
||||
flag = expr_width() == w;
|
||||
break;
|
||||
}
|
||||
expr_width(w);
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: set_width.cc,v $
|
||||
* Revision 1.6 1999/10/05 06:19:46 steve
|
||||
* Add support for reduction NOR.
|
||||
*
|
||||
* Revision 1.5 1999/10/05 04:02:10 steve
|
||||
* Relaxed width handling for <= assignment.
|
||||
*
|
||||
* Revision 1.4 1999/09/29 00:42:51 steve
|
||||
* Allow expanding of additive operators.
|
||||
*
|
||||
* Revision 1.3 1999/09/23 03:56:57 steve
|
||||
* Support shift operators.
|
||||
*
|
||||
* Revision 1.2 1999/09/23 02:27:50 steve
|
||||
* comparison parameter width is self determined.
|
||||
*
|
||||
* Revision 1.1 1999/09/23 00:21:55 steve
|
||||
* Move set_width methods into a single file,
|
||||
* Add the NetEBLogic class for logic expressions,
|
||||
* Fix error setting with of && in if statements.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: t-null.cc,v 1.4 1999/07/03 02:12:52 steve Exp $"
|
||||
#ident "$Id: t-null.cc,v 1.8 1999/10/05 03:26:37 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -33,19 +33,36 @@ static class target_null_t : public target_t {
|
||||
void bufz(ostream&os, const NetBUFZ*) { }
|
||||
void memory(ostream&, const NetMemory*) { }
|
||||
void task_def(ostream&, const NetTaskDef*) { }
|
||||
void net_assign(ostream&os, const NetAssign*) { }
|
||||
void net_assign_nb(ostream&os, const NetAssignNB*) { }
|
||||
void net_esignal(ostream&, const NetESignal*) { }
|
||||
void net_event(ostream&, const NetNEvent*) { }
|
||||
void proc_block(ostream&, const NetBlock*) { }
|
||||
bool proc_block(ostream&, const NetBlock*) { return true; }
|
||||
void proc_condit(ostream&, const NetCondit*) { }
|
||||
void proc_delay(ostream&, const NetPDelay*) { }
|
||||
void proc_event(ostream&, const NetPEvent*) { }
|
||||
void proc_forever(ostream&, const NetForever*) { }
|
||||
void proc_repeat(ostream&, const NetRepeat*) { }
|
||||
void proc_stask(ostream&, const NetSTask*) { }
|
||||
void proc_utask(ostream&os, const NetUTask*) { }
|
||||
|
||||
} target_null_obj;
|
||||
|
||||
extern const struct target tgt_null = { "null", &target_null_obj };
|
||||
/*
|
||||
* $Log: t-null.cc,v $
|
||||
* Revision 1.8 1999/10/05 03:26:37 steve
|
||||
* null target ignore assignment nodes.
|
||||
*
|
||||
* Revision 1.7 1999/09/30 21:27:29 steve
|
||||
* Ignore user task definitions.
|
||||
*
|
||||
* Revision 1.6 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.5 1999/09/17 02:06:26 steve
|
||||
* Handle unconnected module ports.
|
||||
*
|
||||
* Revision 1.4 1999/07/03 02:12:52 steve
|
||||
* Elaborate user defined tasks.
|
||||
*
|
||||
|
||||
+7
-3
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: t-verilog.cc,v 1.7 1999/08/01 16:34:50 steve Exp $"
|
||||
#ident "$Id: t-verilog.cc,v 1.8 1999/09/22 16:57:24 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -43,7 +43,7 @@ class target_verilog : public target_t {
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
virtual void bufz(ostream&os, const NetBUFZ*);
|
||||
virtual void start_process(ostream&os, const NetProcTop*);
|
||||
virtual void proc_block(ostream&os, const NetBlock*);
|
||||
virtual bool proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_delay(ostream&os, const NetPDelay*);
|
||||
virtual void proc_event(ostream&os, const NetPEvent*);
|
||||
virtual void proc_stask(ostream&os, const NetSTask*);
|
||||
@@ -173,13 +173,14 @@ void target_verilog::emit_expr_(ostream&os, const NetExpr*expr)
|
||||
}
|
||||
}
|
||||
|
||||
void target_verilog::proc_block(ostream&os, const NetBlock*net)
|
||||
bool target_verilog::proc_block(ostream&os, const NetBlock*net)
|
||||
{
|
||||
os << setw(indent_) << "" << "begin" << endl;
|
||||
indent_ += 4;
|
||||
net->emit_recurse(os, this);
|
||||
indent_ -= 4;
|
||||
os << setw(indent_) << "" << "end" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void target_verilog::proc_delay(ostream&os, const NetPDelay*net)
|
||||
@@ -271,6 +272,9 @@ const struct target tgt_verilog = {
|
||||
|
||||
/*
|
||||
* $Log: t-verilog.cc,v $
|
||||
* Revision 1.8 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.7 1999/08/01 16:34:50 steve
|
||||
* Parse and elaborate rise/fall/decay times
|
||||
* for gates, and handle the rules for partial
|
||||
|
||||
@@ -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.7 1999/07/17 03:39:11 steve Exp $"
|
||||
#ident "$Id: t-xnf.cc,v 1.9 1999/08/25 22:22:08 steve Exp $"
|
||||
#endif
|
||||
|
||||
/* XNF BACKEND
|
||||
@@ -71,6 +71,7 @@ class target_xnf : public target_t {
|
||||
void end_design(ostream&os, const Design*);
|
||||
void signal(ostream&os, const NetNet*);
|
||||
void logic(ostream&os, const NetLogic*);
|
||||
void bufz(ostream&os, const NetBUFZ*);
|
||||
void udp(ostream&os, const NetUDP*);
|
||||
|
||||
private:
|
||||
@@ -82,7 +83,7 @@ class target_xnf : public target_t {
|
||||
};
|
||||
|
||||
/*
|
||||
* This function takes a signal name and mangles it into an equivilent
|
||||
* This function takes a signal name and mangles it into an equivalent
|
||||
* name that is suitable to the XNF format.
|
||||
*/
|
||||
string target_xnf::mangle(const string&name)
|
||||
@@ -313,6 +314,21 @@ void target_xnf::logic(ostream&os, const NetLogic*net)
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
void target_xnf::bufz(ostream&os, const NetBUFZ*net)
|
||||
{
|
||||
static int warned_once=0;
|
||||
if (!warned_once) {
|
||||
cerr << "Warning: BUFZ object found for xnf output."
|
||||
" Try -Fnobufz." << endl;
|
||||
warned_once=1;
|
||||
}
|
||||
os << "SYM, " << mangle(net->name()) << ", BUF, LIBVER=2.0.0" << endl;
|
||||
assert(net->pin_count() == 2);
|
||||
draw_pin(os, "O", net->pin(0));
|
||||
draw_pin(os, "I", net->pin(1));
|
||||
os << "END" << endl;
|
||||
}
|
||||
|
||||
void target_xnf::udp(ostream&os, const NetUDP*net)
|
||||
{
|
||||
string lca = net->attribute("XNF-LCA");
|
||||
@@ -333,6 +349,12 @@ extern const struct target tgt_xnf = { "xnf", &target_xnf_obj };
|
||||
|
||||
/*
|
||||
* $Log: t-xnf.cc,v $
|
||||
* Revision 1.9 1999/08/25 22:22:08 steve
|
||||
* handle bufz in XNF backend.
|
||||
*
|
||||
* Revision 1.8 1999/08/18 04:00:02 steve
|
||||
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
|
||||
*
|
||||
* Revision 1.7 1999/07/17 03:39:11 steve
|
||||
* simplified process scan for targets.
|
||||
*
|
||||
|
||||
@@ -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.15 1999/07/17 19:51:00 steve Exp $"
|
||||
#ident "$Id: target.cc,v 1.20 1999/09/22 16:57:24 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "target.h"
|
||||
@@ -41,6 +41,12 @@ void target_t::memory(ostream&os, const NetMemory*)
|
||||
"Unhandled memory." << endl;
|
||||
}
|
||||
|
||||
void target_t::func_def(ostream&os, const NetFuncDef*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled function definition." << endl;
|
||||
}
|
||||
|
||||
void target_t::task_def(ostream&os, const NetTaskDef*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
@@ -63,6 +69,12 @@ void target_t::udp(ostream&os, const NetUDP*)
|
||||
"Unhandled UDP." << endl;
|
||||
}
|
||||
|
||||
void target_t::lpm_add_sub(ostream&, const NetAddSub*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled NetAddSub." << endl;
|
||||
}
|
||||
|
||||
void target_t::net_assign(ostream&os, const NetAssign*)
|
||||
{
|
||||
}
|
||||
@@ -79,21 +91,23 @@ void target_t::net_const(ostream&os, const NetConst*)
|
||||
"Unhandled CONSTANT node." << endl;
|
||||
}
|
||||
|
||||
void target_t::net_esignal(ostream&os, const NetESignal*)
|
||||
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*)
|
||||
void target_t::net_event(ostream&os, const NetNEvent*net)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled EVENT net node." << endl;
|
||||
net->dump_node(cerr, 4);
|
||||
}
|
||||
|
||||
void target_t::process(ostream&os, const NetProcTop*top)
|
||||
bool target_t::process(ostream&os, const NetProcTop*top)
|
||||
{
|
||||
top->statement()->emit_proc(os, this);
|
||||
return top->statement()->emit_proc(os, this);
|
||||
}
|
||||
|
||||
void target_t::proc_assign(ostream&os, const NetAssign*)
|
||||
@@ -114,10 +128,17 @@ void target_t::proc_assign_nb(ostream&os, const NetAssignNB*)
|
||||
"Unhandled non-blocking assignment." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_block(ostream&os, const NetBlock*)
|
||||
void target_t::proc_assign_mem_nb(ostream&os, const NetAssignMemNB*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled non-blocking memory assignment." << endl;
|
||||
}
|
||||
|
||||
bool target_t::proc_block(ostream&os, const NetBlock*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_block." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_case(ostream&os, const NetCase*cur)
|
||||
@@ -140,10 +161,11 @@ void target_t::proc_delay(ostream&os, const NetPDelay*)
|
||||
"Unhandled proc_delay." << endl;
|
||||
}
|
||||
|
||||
void target_t::proc_event(ostream&os, const NetPEvent*)
|
||||
void target_t::proc_event(ostream&os, const NetPEvent*net)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_event." << endl;
|
||||
net->dump(cerr, 4);
|
||||
}
|
||||
|
||||
void target_t::proc_forever(ostream&os, const NetForever*)
|
||||
@@ -227,6 +249,12 @@ void expr_scan_t::expr_ternary(const NetETernary*)
|
||||
"unhandled expr_ternary." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_ufunc(const NetEUFunc*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
"unhandled function call." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_unary(const NetEUnary*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
@@ -241,6 +269,21 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
|
||||
|
||||
/*
|
||||
* $Log: target.cc,v $
|
||||
* Revision 1.20 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.19 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.18 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* Revision 1.17 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.16 1999/08/18 04:00:02 steve
|
||||
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
|
||||
*
|
||||
* Revision 1.15 1999/07/17 19:51:00 steve
|
||||
* netlist support for ternary operator.
|
||||
*
|
||||
|
||||
@@ -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.15 1999/07/17 19:51:00 steve Exp $"
|
||||
#ident "$Id: target.h,v 1.19 1999/09/22 16:57:24 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "netlist.h"
|
||||
@@ -63,6 +63,10 @@ struct target_t {
|
||||
|
||||
/* Output a defined task. */
|
||||
virtual void task_def(ostream&, const NetTaskDef*);
|
||||
virtual void func_def(ostream&, const NetFuncDef*);
|
||||
|
||||
/* LPM style components are handled here. */
|
||||
virtual void lpm_add_sub(ostream&os, const NetAddSub*);
|
||||
|
||||
/* Output a gate (called for each gate) */
|
||||
virtual void logic(ostream&os, const NetLogic*);
|
||||
@@ -76,13 +80,14 @@ struct target_t {
|
||||
|
||||
/* Output a process (called for each process). It is up to the
|
||||
target to recurse if desired. */
|
||||
virtual void process(ostream&os, const NetProcTop*);
|
||||
virtual bool process(ostream&os, const NetProcTop*);
|
||||
|
||||
/* Various kinds of process nodes are dispatched through these. */
|
||||
virtual void proc_assign(ostream&os, const NetAssign*);
|
||||
virtual void proc_assign_mem(ostream&os, const NetAssignMem*);
|
||||
virtual void proc_assign_nb(ostream&os, const NetAssignNB*);
|
||||
virtual void proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_assign_mem_nb(ostream&os, const NetAssignMemNB*);
|
||||
virtual bool proc_block(ostream&os, const NetBlock*);
|
||||
virtual void proc_case(ostream&os, const NetCase*);
|
||||
virtual void proc_condit(ostream&os, const NetCondit*);
|
||||
virtual void proc_forever(ostream&os, const NetForever*);
|
||||
@@ -109,6 +114,7 @@ struct expr_scan_t {
|
||||
virtual void expr_signal(const NetESignal*);
|
||||
virtual void expr_subsignal(const NetESubSignal*);
|
||||
virtual void expr_ternary(const NetETernary*);
|
||||
virtual void expr_ufunc(const NetEUFunc*);
|
||||
virtual void expr_unary(const NetEUnary*);
|
||||
virtual void expr_binary(const NetEBinary*);
|
||||
};
|
||||
@@ -117,7 +123,7 @@ struct expr_scan_t {
|
||||
/* The emit functions take a design and emit it to the output stream
|
||||
using the specified target. If the target is given by name, it is
|
||||
located in the target_table and used. */
|
||||
extern void emit(ostream&o, const Design*des, const char*type);
|
||||
extern bool emit(ostream&o, const Design*des, const char*type);
|
||||
|
||||
/* This function takes a fully qualified verilog name (which may have,
|
||||
for example, dots in it) and produces a mangled version that can be
|
||||
@@ -130,6 +136,18 @@ extern const struct target *target_table[];
|
||||
|
||||
/*
|
||||
* $Log: target.h,v $
|
||||
* Revision 1.19 1999/09/22 16:57:24 steve
|
||||
* Catch parallel blocks in vvm emit.
|
||||
*
|
||||
* Revision 1.18 1999/09/15 01:55:06 steve
|
||||
* Elaborate non-blocking assignment to memories.
|
||||
*
|
||||
* Revision 1.17 1999/09/03 04:28:38 steve
|
||||
* elaborate the binary plus operator.
|
||||
*
|
||||
* Revision 1.16 1999/08/31 22:38:29 steve
|
||||
* Elaborate and emit to vvm procedural functions.
|
||||
*
|
||||
* Revision 1.15 1999/07/17 19:51:00 steve
|
||||
* netlist support for ternary operator.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
.TH verilog 1 "Septemeber 13th, 1999" Version 19990913
|
||||
.SH NAME
|
||||
verilog - Icarus Verilog Driver
|
||||
.SH SYNOPSIS
|
||||
.B verilog
|
||||
[-Dmacro[=defn]] [-Iincludepath] [-X] [-o outputfilename] [-s topmodule] sourcefile[s]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fIverilog\fP is the compiler driver script for compiling Verilog code
|
||||
to either a VVM-format (Verilog Virtual Machine) for simulation or to
|
||||
XNF (Xilinx Netlist Format) to be used in Xilinx FPGA's.
|
||||
|
||||
\fIverilog\fP is just massaging the input switches and then calls
|
||||
the preprocessor (ivlpp), the compiler (ivl) and (optional) the C++
|
||||
compiler.
|
||||
|
||||
Please read the official documentation (very minimal at this point)
|
||||
on how to use \fIivl et al\fP, since this man page just describes the
|
||||
"easy startscript" \fIverilog\fP.
|
||||
|
||||
.SH OPTIONS
|
||||
.l
|
||||
\fIverilog\fP accepts the following options:
|
||||
.TP 8
|
||||
.B -D\fImacro\fP
|
||||
Defines macro \fImacro\fP with the string `1' as its definition.
|
||||
.TP 8
|
||||
.B -D\fImacro=defn\fP
|
||||
Defines macro \fImacro\fP as \fIdefn\fP.
|
||||
.TP 8
|
||||
.B -I\fIincludepath\fP
|
||||
Append path \fIincludepath\fP to list of paths searched for include files.
|
||||
.TP 8
|
||||
.B -X
|
||||
Generate XNF files as output. Default is VVM-format.
|
||||
.TP 8
|
||||
.B -x
|
||||
Executes the generated file directly after compilation.
|
||||
.TP 8
|
||||
.B -o \fIfilename\fP
|
||||
Place output in the file \fIfilename\fP. If not given, \fIverilog\fP tries to
|
||||
make a guess; if the input filename is "hello.v", the output
|
||||
filename will be "hello" (for VVM target) or "hello.xnf" (for XNF target).
|
||||
If several files are given on the command line, the \fIlast\fP filename will
|
||||
be used.
|
||||
.TP 8
|
||||
.B -s \fItopmodule name\fP
|
||||
To explicitly set the module \fIivl\fP will use as a top-level module.
|
||||
|
||||
.SH EXAMPLES
|
||||
These examples assume that you have a Verilog source file called hello.v in
|
||||
the current directory
|
||||
|
||||
To compile hello.v to an executable file called hello:
|
||||
|
||||
verilog hello.v
|
||||
|
||||
To compile hello.v to an executable file called runnable:
|
||||
|
||||
verilog -o runnable hello.v
|
||||
|
||||
To compile hello.v to a file in XNF-format called hello.xnf
|
||||
|
||||
verilog -X hello.v
|
||||
|
||||
|
||||
.SH "ENVIRONMENT"
|
||||
.ta \w'VPI_MODULE_PATH 'u
|
||||
VPI_MODULE_PATH path to PLI modules
|
||||
|
||||
.SH "AUTHORS"
|
||||
.nf
|
||||
.ta \w'verilog 'u
|
||||
verilog Stefan Petersen ([email protected])
|
||||
ivlpp Steve Williams ([email protected])
|
||||
ivl Steve Williams ([email protected])
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR ivlpp (N/A)
|
||||
.BR ivl (N/A)
|
||||
.SH COPYRIGHT
|
||||
.nf
|
||||
Copyright \(co 1999 Stefan Petersen
|
||||
|
||||
This document can be freely redistributed according to the terms of the
|
||||
GNU General Public License version 2.0
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
#!/bin/sh
|
||||
|
||||
# verilog - A wrapper shell script for ivl
|
||||
# Copyright (C) 1999 Stefan Petersen ([email protected])
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
|
||||
# Setup variables
|
||||
execPath=@bindir@
|
||||
execIVLPP=${execPath}/ivlpp
|
||||
execIVL=${execPath}/ivl
|
||||
execCpp=/usr/bin/g++
|
||||
|
||||
vvmTarget="-t vvm"
|
||||
xnfTarget="-t xnf"
|
||||
|
||||
tmpDir=/tmp
|
||||
tmpPPFile=${tmpDir}/ivl$$.pp
|
||||
tmpCCFile=${tmpDir}/ivl$$.cc
|
||||
|
||||
VPIModulePath=@libdir@/ivl:.
|
||||
|
||||
target=${vvmTarget}
|
||||
targetSuffix=""
|
||||
|
||||
# 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 "To be able to execute, set VPI_MODULE_PATH to ${VPIModulePath}";
|
||||
fi
|
||||
|
||||
# Try to extract given parameters
|
||||
parameter=`getopt D:I:Xxo:s: "$@"`
|
||||
eval set -- "${parameter}"
|
||||
while true ; do
|
||||
|
||||
case "$1" in
|
||||
-D) extDefines="${extDefines} -D$2" ; shift 2 ;;
|
||||
-I) extIncPath="${extIncPath} -I $2" ; shift 2 ;;
|
||||
-X) targetSuffix=".xnf" ; target=${xnfTarget} ; shift ;;
|
||||
-o) outputFile=$2 ; shift 2 ;;
|
||||
-s) topModule="-s $2 " ; shift 2 ;;
|
||||
-x) execute="true"; shift ;;
|
||||
--) shift ; break ;;
|
||||
*) echo "Internal error! Arg is $1 " ; exit 1 ;;
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
# The rest is filenames
|
||||
verilogFile=$@;
|
||||
|
||||
if test -z "${verilogFile}" ; then
|
||||
echo "Missing infile";
|
||||
echo "verilog [-Dmacro[=defn]] [-Iincludepath] [-X] [-x] [-o outputfilename] [-s topmodule] sourcefile[s]" ;
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
|
||||
# If no output file is given should we guess one or...?
|
||||
# Assumes a few silly things if several files are given
|
||||
if test -z "${outputFile}" ; then
|
||||
outputFile=`echo ${verilogFile} | sed -e 's;.* ;;' | sed -e 's;\..*$;;'`
|
||||
outputFile="${outputFile}${targetSuffix}" ;
|
||||
fi
|
||||
|
||||
# Preprocess
|
||||
${execIVLPP} ${extDefines} ${extIncPath} -L -o ${tmpPPFile} ${verilogFile}
|
||||
if test $? -ne 0 ; then
|
||||
echo "Preprocessing failed. Terminating compilation."
|
||||
rm -f ${tmpPPFile}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Compile preprocessed verilog file
|
||||
${execIVL} ${target} -o ${tmpCCFile} ${topModule} ${tmpPPFile}
|
||||
if test $? -ne 0 ; then
|
||||
echo "Verilog compilation failed. Terminating compilation."
|
||||
rm -f ${tmpCCFile}
|
||||
exit 1
|
||||
fi
|
||||
rm -f ${tmpPPFile}
|
||||
|
||||
|
||||
case "${targetSuffix}" in
|
||||
|
||||
.xnf) mv ${tmpCCFile} ${outputFile} ;;
|
||||
|
||||
"") ${execCpp} -rdynamic ${tmpCCFile} -o ${outputFile} -lvvm -ldl ;
|
||||
if test $? -ne 0 ; then
|
||||
echo "C++ compilation failed. Terminating compilation."
|
||||
rm -f ${tmpCCFile}
|
||||
exit 1
|
||||
fi
|
||||
rm -f ${tmpCCFile} ;;
|
||||
|
||||
*) echo "Internal error in target compilation." ; exit 1
|
||||
|
||||
esac
|
||||
|
||||
if test ${execute} ; then
|
||||
./${outputFile}
|
||||
fi
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
HOW IT WORKS
|
||||
|
||||
The VPI interface for Icarus Verilog works by creating from a
|
||||
collection of PLI applications a single vpi module. The vpi module
|
||||
includes compiled code for the applications linked together (with any
|
||||
other libraries that the applications need) into a module with a
|
||||
single exported symbol, the vlog_startup_routines array.
|
||||
|
||||
The product that wishes to invoke the module (normally at run time)
|
||||
loads the module, locates the vlog_startup_routines table, and calls
|
||||
all the startup routines contained in that table. It is possible for a
|
||||
product to link with many modules. In that case, all the modules are
|
||||
linked in and startup routines are called in order.
|
||||
|
||||
The product that uses vpi modules uses the environment variable
|
||||
VPI_MODULE_PATH as a ':' separated list of directories. This is the
|
||||
module search path. When a module is specified by name (using whatever
|
||||
means the product supports) the module search path is scanned until
|
||||
the module is located.
|
||||
|
||||
The special module name "system.vpi" is part of the core Icarus
|
||||
Verilog distribution and includes implementations of the standard
|
||||
system tasks/functions.
|
||||
|
||||
COMPILING A VPI MODULE (LINUX)
|
||||
|
||||
To compile a module, first compile down to object files all the PLI
|
||||
applications that you wish to include in the module. Then, create a
|
||||
small "C" source file that defines only the startup table like so:
|
||||
|
||||
extern void hello_register();
|
||||
void (*vlog_startup_routines[])() = {
|
||||
hello_register,
|
||||
0
|
||||
};
|
||||
|
||||
Compile this table source down to its object file, as well. Finally,
|
||||
link the application with the command:
|
||||
|
||||
cc -o foo.vpi -shared <all the .o files>
|
||||
|
||||
No VPI libraries need to be included because the product that loads
|
||||
the module will supply all the standard vpi functions. If you use any
|
||||
non-vpi library functions, you may need to include libraries to
|
||||
support them.
|
||||
|
||||
The resulting foo.vpi file is the vpi module. Place it in a location
|
||||
where the product to use it can locate it.
|
||||
|
||||
|
||||
CAVEAT EMPTOR
|
||||
|
||||
Only the calltf function is supported. The compiletf and sizetf
|
||||
functions are invoked at compile time, and the ivl compiler does not
|
||||
yet support VPI.
|
||||
@@ -0,0 +1,3 @@
|
||||
Makefile
|
||||
system.vpi
|
||||
dep
|
||||
@@ -0,0 +1,81 @@
|
||||
#
|
||||
# This source code is free software; you can redistribute it
|
||||
# and/or modify it in source code form under the terms of the GNU
|
||||
# Library 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 Library General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Library 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
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.4 1999/08/31 23:00:08 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
srcdir = @srcdir@
|
||||
|
||||
VPATH = $(srcdir)
|
||||
|
||||
bindir = $(exec_prefix)/bin
|
||||
libdir = $(exec_prefix)/lib
|
||||
includedir = $(prefix)/include
|
||||
|
||||
CC = @CC@
|
||||
CXX = @CXX@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@ @DEFS@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: system.vpi
|
||||
|
||||
%.o dep/%.d: %.c
|
||||
@[ -d dep ] || mkdir dep
|
||||
$(CC) -Wall $(CPPFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = sys_table.o sys_display.o sys_finish.o
|
||||
|
||||
system.vpi: $O
|
||||
$(CC) -shared -o $@ $O
|
||||
|
||||
clean:
|
||||
rm -f *.o dep/*.d
|
||||
|
||||
install: all installdirs $(libdir)/ivl/system.vpi \
|
||||
$(includedir)/vpi_user.h
|
||||
|
||||
$(libdir)/ivl/system.vpi: ./system.vpi
|
||||
$(INSTALL_PROGRAM) ./system.vpi $(libdir)/ivl/system.vpi
|
||||
|
||||
$(includedir)/vpi_user.h: $(srcdir)/vpi_user.h
|
||||
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(includedir)/vpi_user.h
|
||||
|
||||
|
||||
installdirs: ../mkinstalldirs
|
||||
$(srcdir)/../mkinstalldirs $(includedir) $(bindir) $(libdir)/ivl
|
||||
|
||||
uninstall:
|
||||
rm -f $(libdir)/ivl/system.vpi
|
||||
rm -f $(includedir)/vpi_user.h
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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_display.c,v 1.2 1999/09/29 01:41:18 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
# include <assert.h>
|
||||
# include <string.h>
|
||||
# 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;
|
||||
|
||||
value.format = vpiBinStrVal;
|
||||
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));
|
||||
}
|
||||
|
||||
/*
|
||||
* If $display discovers a string as a parameter, this function is
|
||||
* called to process it as a format string. I need the argv handle as
|
||||
* well so that I can look for arguments as I move forward through the
|
||||
* string.
|
||||
*/
|
||||
static void format(s_vpi_value*fmt, vpiHandle argv)
|
||||
{
|
||||
char buf[256];
|
||||
char*cp = fmt->value.str;
|
||||
assert(fmt->value.str);
|
||||
|
||||
while (*cp) {
|
||||
size_t cnt = strcspn(cp, "%\\");
|
||||
if (cnt > 0) {
|
||||
if (cnt >= sizeof buf)
|
||||
cnt = sizeof buf - 1;
|
||||
strncpy(buf, cp, cnt);
|
||||
buf[cnt] = 0;
|
||||
vpi_printf("%s", buf);
|
||||
cp += cnt;
|
||||
|
||||
} else if (*cp == '%') {
|
||||
int fsize = -1;
|
||||
|
||||
cp += 1;
|
||||
if (isdigit(*cp))
|
||||
fsize = strtoul(cp, &cp, 10);
|
||||
|
||||
switch (*cp) {
|
||||
case 0:
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
format_binary(argv, fsize);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
format_decimal(argv, fsize);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
case 'x':
|
||||
case 'X':
|
||||
format_hex(argv, fsize);
|
||||
cp += 1;
|
||||
break;
|
||||
case 'm':
|
||||
format_m(argv, fsize);
|
||||
cp += 1;
|
||||
break;
|
||||
case '%':
|
||||
vpi_printf("%%");
|
||||
cp += 1;
|
||||
break;
|
||||
default:
|
||||
vpi_printf("%c", *cp);
|
||||
cp += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
cp += 1;
|
||||
switch (*cp) {
|
||||
case 0:
|
||||
break;
|
||||
case 'n':
|
||||
vpi_printf("\n");
|
||||
cp += 1;
|
||||
break;
|
||||
default:
|
||||
vpi_printf("%c", *cp);
|
||||
cp += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sys_display_calltf(char *name)
|
||||
{
|
||||
s_vpi_value value;
|
||||
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
|
||||
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle item;
|
||||
|
||||
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
case 0:
|
||||
vpi_printf(" ");
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%s", value.value.str);
|
||||
break;
|
||||
|
||||
case vpiTimeVar:
|
||||
value.format = vpiTimeVal;
|
||||
vpi_get_value(item, &value);
|
||||
vpi_printf("%u", value.value.time->low);
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_printf("?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(name,"$display") == 0)
|
||||
vpi_printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_display_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$display";
|
||||
tf_data.calltf = sys_display_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$display";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$write";
|
||||
tf_data.calltf = sys_display_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$write";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: sys_display.c,v $
|
||||
* Revision 1.2 1999/09/29 01:41:18 steve
|
||||
* Support the $write system task, and have the
|
||||
* vpi_scan function free iterators as needed.
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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_finish.c,v 1.3 1999/08/28 02:10:44 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
|
||||
static int sys_finish_calltf(char *xx)
|
||||
{
|
||||
vpi_sim_control(vpiFinish, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_finish_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$finish";
|
||||
tf_data.calltf = sys_finish_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: sys_finish.c,v $
|
||||
* Revision 1.3 1999/08/28 02:10:44 steve
|
||||
* Call the right vpiFinish code.
|
||||
*
|
||||
* Revision 1.2 1999/08/19 02:51:03 steve
|
||||
* Add vpi_sim_control
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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_table.c,v 1.1 1999/08/15 01:23:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
extern void sys_finish_register();
|
||||
extern void sys_display_register();
|
||||
|
||||
void (*vlog_startup_routines[])() = {
|
||||
sys_finish_register,
|
||||
sys_display_register,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* $Log: sys_table.c,v $
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
#ifndef __vpi_user_H
|
||||
#define __vpi_user_H
|
||||
/*
|
||||
* 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_user.h,v 1.3 1999/08/19 02:51:03 steve Exp $"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct __vpiHandle *vpiHandle;
|
||||
|
||||
/*
|
||||
* This structure is created by the VPI application to provide hooks
|
||||
* into the application that the compiler/simulator can access.
|
||||
*/
|
||||
typedef struct t_vpi_systf_data {
|
||||
int type;
|
||||
int subtype;
|
||||
char *tfname;
|
||||
int (*calltf)(char*);
|
||||
int (*compiletf)(char*);
|
||||
int (*sizetf)();
|
||||
char *user_data;
|
||||
} s_vpi_systf_data, *p_vpi_systf_data;
|
||||
|
||||
/* The type in the above structure can have one of the following
|
||||
values: */
|
||||
#define vpiSysTask 1
|
||||
#define vpiSysFunc 2
|
||||
|
||||
|
||||
typedef struct t_vpi_time {
|
||||
int type;
|
||||
unsigned int high;
|
||||
unsigned int low;
|
||||
double real;
|
||||
} s_vpi_time, *p_vpi_time;
|
||||
|
||||
#define vpiScaledRealTime 1
|
||||
#define vpiSimTime 2
|
||||
#define vpiSuppressTime 3
|
||||
|
||||
/*
|
||||
* This structure holds values that are passed back and forth between
|
||||
* the simulator and the application.
|
||||
*/
|
||||
typedef struct t_vpi_value {
|
||||
int format;
|
||||
union {
|
||||
char*str;
|
||||
int scalar;
|
||||
int integer;
|
||||
double real;
|
||||
struct t_vpi_time *time;
|
||||
struct t_vpi_vecval *vector;
|
||||
struct t_vpi_strengthval *strength;
|
||||
char*misc;
|
||||
} value;
|
||||
} s_vpi_value, *p_vpi_value;
|
||||
|
||||
/* These are valid codes for the format of the t_vpi_value structure. */
|
||||
#define vpiBinStrVal 1
|
||||
#define vpiOctStrVal 2
|
||||
#define vpiDecStrVal 3
|
||||
#define vpiHexStrVal 4
|
||||
#define vpiScalerVal 5
|
||||
#define vpiIntVal 6
|
||||
#define vpiReadVal 7
|
||||
#define vpiStringVal 8
|
||||
#define vpiVectorVal 9
|
||||
#define vpiStrengthVal 10
|
||||
#define vpiTimeVal 11
|
||||
#define vpiObjTypeVal 12
|
||||
#define vpiSuppressVal 13
|
||||
|
||||
|
||||
/* OBJECT CODES */
|
||||
#define vpiConstant 7
|
||||
#define vpiNet 36
|
||||
#define vpiReg 48
|
||||
#define vpiSysTaskCall 57
|
||||
#define vpiTimeVar 63
|
||||
#define vpiSysTfCall 85
|
||||
#define vpiArgument 89
|
||||
|
||||
|
||||
/* PROPERTIES */
|
||||
#define vpiType 1
|
||||
#define vpiName 2
|
||||
#define vpiFullName 3
|
||||
#define vpiConstType 43
|
||||
# define vpiDecConst 1
|
||||
# define vpiRealConst 2
|
||||
# define vpiBinaryConst 3
|
||||
# define vpiOctConst 4
|
||||
# define vpiHexConst 5
|
||||
# define vpiStringConst 6
|
||||
|
||||
|
||||
/* VPI FUNCTIONS */
|
||||
extern void vpi_register_systf(const struct t_vpi_systf_data*ss);
|
||||
extern void vpi_printf(const char*fmt, ...);
|
||||
|
||||
/*
|
||||
* This function allows a vpi application to control the simulation
|
||||
* engine. The operation parameter specifies the function to
|
||||
* perform. The remaining parameters (if any) are interpreted by the
|
||||
* operation. The vpi_sim_control definition was added to P1364-2000
|
||||
* 14 July 1999. See PLI Task Force ID: PTF-161
|
||||
*
|
||||
* vpiFinish - perform the $finish operation, as soon as the user
|
||||
* function returns. This operation takes a single
|
||||
* parameter, a diagnostic exit code.
|
||||
*
|
||||
* vpiStop -
|
||||
* vpiReset -
|
||||
* vpiSetInteractiveScope -
|
||||
*/
|
||||
extern void vpi_sim_control(int operation, ...);
|
||||
#define vpiStop 1
|
||||
#define vpiFinish 2
|
||||
#define vpiReset 3
|
||||
#define vpiSetInteractiveScope 4
|
||||
|
||||
extern vpiHandle vpi_handle(int type, vpiHandle ref);
|
||||
extern vpiHandle vpi_iterate(int type, vpiHandle ref);
|
||||
extern vpiHandle vpi_scan(vpiHandle iter);
|
||||
|
||||
extern int vpi_get(int property, vpiHandle ref);
|
||||
extern char* vpi_get_str(int property, vpiHandle ref);
|
||||
extern void vpi_get_value(vpiHandle expr, p_vpi_value value);
|
||||
|
||||
extern int vpi_free_object(vpiHandle ref);
|
||||
|
||||
|
||||
/* This is the table of startup routines included in each module. */
|
||||
extern void (*vlog_startup_routines[])();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $Log: vpi_user.h,v $
|
||||
* Revision 1.3 1999/08/19 02:51:03 steve
|
||||
* Add vpi_sim_control
|
||||
*
|
||||
* Revision 1.2 1999/08/18 03:44:49 steve
|
||||
* declare vou_sim_control
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -16,6 +16,17 @@ So a sample command line to compile a Verilog file to C++ would be:
|
||||
|
||||
ivl -F nobufz -F sigfold -F propinit -t vvm -o foo.cc foo.vl
|
||||
|
||||
Once the program is compiled down to C++ code, it needs to be further
|
||||
compiled and linked into an executable image. The command for doing
|
||||
this is highly dependent on the system where you use Icarus
|
||||
Verilog. For Linux, the compile command is typically:
|
||||
|
||||
c++ -rdynamic -o foo foo.cc -lvvm -ldl
|
||||
|
||||
On any system, the compiled program requires that the VPI_MODULE_PATH
|
||||
be set to a ':' separated list of directories to search for vpi files,
|
||||
the system.vpi file in particular. This is a run time requirement.
|
||||
|
||||
ATTRIBUTES
|
||||
|
||||
(none)
|
||||
@@ -99,8 +110,14 @@ bits are at:
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
$Id: vvm.txt,v 1.1 1999/04/29 16:29:04 steve Exp $
|
||||
$Id: vvm.txt,v 1.3 1999/08/18 03:45:36 steve Exp $
|
||||
$Log: vvm.txt,v $
|
||||
Revision 1.3 1999/08/18 03:45:36 steve
|
||||
Update compile command line.
|
||||
|
||||
Revision 1.2 1999/08/15 01:23:56 steve
|
||||
Convert vvm to implement system tasks with vpi.
|
||||
|
||||
Revision 1.1 1999/04/29 16:29:04 steve
|
||||
Add vvm target documentation
|
||||
|
||||
|
||||
+10
-6
@@ -18,7 +18,7 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.3 1999/05/09 01:24:59 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.5 1999/08/28 02:10:57 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
@@ -36,7 +36,7 @@ libdir = $(exec_prefix)/lib
|
||||
includedir = $(prefix)/include
|
||||
|
||||
CC = @CC@
|
||||
CXX = @CXX@
|
||||
CXX = @CXX@ -I../vpi
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
@@ -52,9 +52,8 @@ all: libvvm.a
|
||||
$(CXX) -Wall -fno-exceptions $(CXXFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
TF = display.o
|
||||
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_monitor.o vvm_pevent.o \
|
||||
vvm_simulation.o vvm_thread.o $(TF)
|
||||
vvm_simulation.o vvm_thread.o
|
||||
|
||||
libvvm.a: $O
|
||||
rm -f $@
|
||||
@@ -65,10 +64,11 @@ clean:
|
||||
|
||||
install: all installdirs $(libdir)/libvvm.a \
|
||||
$(includedir)/vvm.h \
|
||||
$(includedir)/vvm_calltf.h \
|
||||
$(includedir)/vpi_priv.h \
|
||||
$(includedir)/vvm_func.h \
|
||||
$(includedir)/vvm_gates.h \
|
||||
$(includedir)/vvm_thread.h
|
||||
$(includedir)/vvm_thread.h \
|
||||
$(includedir)/vvm_calltf.h
|
||||
|
||||
$(libdir)/libvvm.a: ./libvvm.a
|
||||
$(INSTALL_PROGRAM) ./libvvm.a $(libdir)/libvvm.a
|
||||
@@ -88,6 +88,9 @@ $(includedir)/vvm_gates.h: $(srcdir)/vvm_gates.h
|
||||
$(includedir)/vvm_thread.h: $(srcdir)/vvm_thread.h
|
||||
$(INSTALL_DATA) $(srcdir)/vvm_thread.h $(includedir)/vvm_thread.h
|
||||
|
||||
$(includedir)/vpi_priv.h: $(srcdir)/vpi_priv.h
|
||||
$(INSTALL_DATA) $(srcdir)/vpi_priv.h $(includedir)/vpi_priv.h
|
||||
|
||||
installdirs: mkinstalldirs
|
||||
$(srcdir)/mkinstalldirs $(includedir) $(bindir)
|
||||
|
||||
@@ -98,6 +101,7 @@ uninstall:
|
||||
rm -f $(includedir)/vvm_func.h
|
||||
rm -f $(includedir)/vvm_gates.h
|
||||
rm -f $(includedir)/vvm_thread.h
|
||||
rm -f $(includedir)/vpi_priv.h
|
||||
|
||||
|
||||
-include $(patsubst %.o, dep/%.d, $O)
|
||||
|
||||
-264
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1998 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: display.cc,v 1.5 1999/05/31 15:46:36 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include "vvm_calltf.h"
|
||||
# include <iostream>
|
||||
|
||||
static void format_hex(vvm_simulation*sim, ostream&os,
|
||||
class vvm_calltf_parm*parm)
|
||||
{
|
||||
switch (parm->type()) {
|
||||
case vvm_calltf_parm::TIME:
|
||||
os << sim->get_sim_time();
|
||||
break;
|
||||
case vvm_calltf_parm::NONE:
|
||||
os << "z";
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
os << ((parm->as_ulong()&1) ? "0" : "1");
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
os << parm->as_string();
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
unsigned c = 0;
|
||||
for (unsigned idx = parm->as_bits()->get_width()
|
||||
; idx > 0 ; idx -= 1)
|
||||
c = (c << 1) | parm->as_bits()->get_bit(idx-1);
|
||||
cout.form("%x",c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void format_bit(vvm_simulation*sim, ostream&os,
|
||||
class vvm_calltf_parm*parm)
|
||||
{
|
||||
switch (parm->type()) {
|
||||
case vvm_calltf_parm::TIME:
|
||||
os << (sim->get_sim_time()&1);
|
||||
break;
|
||||
case vvm_calltf_parm::NONE:
|
||||
os << "z";
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
os << ((parm->as_ulong()&1) ? "0" : "1");
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
os << parm->as_string();
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
for (unsigned idx = parm->as_bits()->get_width()
|
||||
; idx > 0 ; idx -= 1)
|
||||
os << parm->as_bits()->get_bit(idx-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void format_dec(vvm_simulation*sim, ostream&os,
|
||||
class vvm_calltf_parm*parm)
|
||||
{
|
||||
switch (parm->type()) {
|
||||
case vvm_calltf_parm::TIME:
|
||||
os << sim->get_sim_time();
|
||||
break;
|
||||
case vvm_calltf_parm::NONE:
|
||||
os << "0";
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
os << parm->as_ulong();
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
os << parm->as_string();
|
||||
break;
|
||||
case vvm_calltf_parm::BITS: {
|
||||
unsigned long val = 0;
|
||||
unsigned long mask = 1;
|
||||
const vvm_bits_t*bstr = parm->as_bits();
|
||||
for (unsigned idx = 0 ; idx < bstr->get_width() ; idx += 1) {
|
||||
if (bstr->get_bit(idx) == V1) val |= mask;
|
||||
mask <<= 1;
|
||||
}
|
||||
os << val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void format_name(ostream&os, class vvm_calltf_parm*parm)
|
||||
{
|
||||
switch (parm->type()) {
|
||||
case vvm_calltf_parm::TIME:
|
||||
os << "$time";
|
||||
break;
|
||||
case vvm_calltf_parm::NONE:
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
os << parm->as_ulong();
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
os << "\"" << parm->as_string() << "\"";
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
os << parm->sig_name();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned format(vvm_simulation*sim, const string&str,
|
||||
unsigned nparms,
|
||||
class vvm_calltf_parm*parms)
|
||||
{
|
||||
char prev = 0;
|
||||
unsigned next_parm = 0;
|
||||
unsigned idx = 0;
|
||||
while (idx < str.length()) {
|
||||
if (prev == '%') {
|
||||
switch (str[idx]) {
|
||||
case 'b':
|
||||
case 'B':
|
||||
format_bit(sim, cout, parms+next_parm);
|
||||
next_parm += 1;
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'h':
|
||||
case 'H':
|
||||
format_hex(sim, cout, parms+next_parm);
|
||||
next_parm += 1;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
format_dec(sim, cout, parms+next_parm);
|
||||
next_parm += 1;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
format_name(cout, parms+next_parm);
|
||||
next_parm += 1;
|
||||
break;
|
||||
case '%':
|
||||
cout << str[idx];
|
||||
break;
|
||||
}
|
||||
|
||||
prev = 0;
|
||||
|
||||
} else {
|
||||
if (str[idx] != '%')
|
||||
cout << str[idx];
|
||||
else
|
||||
prev = '%';
|
||||
}
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
return next_parm;
|
||||
}
|
||||
|
||||
void Sdisplay(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*parms)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < nparms ; idx += 1)
|
||||
switch (parms[idx].type()) {
|
||||
case vvm_calltf_parm::NONE:
|
||||
cout << " ";
|
||||
break;
|
||||
case vvm_calltf_parm::TIME:
|
||||
cout << sim->get_sim_time();
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
cout << parms[idx].as_ulong();
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
idx += format(sim, parms[idx].as_string(),
|
||||
nparms-idx-1, parms+idx+1);
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
cout << *parms[idx].as_bits();
|
||||
break;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
class monitor_event : public vvm_event {
|
||||
public:
|
||||
monitor_event(vvm_simulation*sim,
|
||||
unsigned nparms, class vvm_calltf_parm*parms)
|
||||
{ sim_ = sim;
|
||||
nparms_ = nparms;
|
||||
parms_ = new vvm_calltf_parm[nparms];
|
||||
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
|
||||
parms_[idx] = parms[idx];
|
||||
}
|
||||
|
||||
~monitor_event() { delete[]parms_; }
|
||||
|
||||
private:
|
||||
vvm_simulation*sim_;
|
||||
unsigned nparms_;
|
||||
vvm_calltf_parm*parms_;
|
||||
void event_function();
|
||||
};
|
||||
|
||||
void monitor_event::event_function()
|
||||
{
|
||||
Sdisplay(sim_, "$display", nparms_, parms_);
|
||||
}
|
||||
|
||||
static monitor_event*mon = 0;
|
||||
|
||||
void Smonitor(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*parms)
|
||||
{
|
||||
if (mon) delete mon;
|
||||
mon = new monitor_event(sim, nparms, parms);
|
||||
|
||||
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
|
||||
if (parms[idx].type() != vvm_calltf_parm::BITS)
|
||||
continue;
|
||||
|
||||
parms[idx].as_mon()->enable(mon);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: display.cc,v $
|
||||
* Revision 1.5 1999/05/31 15:46:36 steve
|
||||
* Handle time in more places.
|
||||
*
|
||||
* Revision 1.4 1999/05/12 04:02:17 steve
|
||||
* Add %x support contributed by Steve Wilson.
|
||||
*
|
||||
* Revision 1.3 1999/01/01 01:44:40 steve
|
||||
* Proberly print vectors in binary.
|
||||
*
|
||||
* Revision 1.2 1998/11/10 00:48:31 steve
|
||||
* Add support it vvm target for level-sensitive
|
||||
* triggers (i.e. the Verilog wait).
|
||||
* Fix display of $time is format strings.
|
||||
*
|
||||
* Revision 1.1 1998/11/09 23:44:10 steve
|
||||
* Add vvm library.
|
||||
*
|
||||
*/
|
||||
@@ -0,0 +1,97 @@
|
||||
#ifndef __vpi_priv_H
|
||||
#define __vpi_priv_H
|
||||
/*
|
||||
* 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_priv.h,v 1.1 1999/08/15 01:23:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is the most basic type in the vpi implementation. A handle can
|
||||
* exist to refer to most any of the supported vpi objects. The
|
||||
* interpretation of the parts depends in general on the type of the
|
||||
* object.
|
||||
*/
|
||||
struct __vpiHandle {
|
||||
int type;
|
||||
int subtype;
|
||||
|
||||
/* These are property values. */
|
||||
char*full_name;
|
||||
|
||||
/* This pointer is used for to-one references. */
|
||||
struct __vpiHandle*referent;
|
||||
|
||||
/* This pointer table is used for to-many refrences to
|
||||
arguments, and is used by the vpiArgument iterator. */
|
||||
struct __vpiHandle**arguments;
|
||||
unsigned narguments;
|
||||
|
||||
/* These methods support the various vpi_get() functions. */
|
||||
int (*get_)(int property, vpiHandle ref);
|
||||
char* (*get_str_)(int property, vpiHandle ref);
|
||||
|
||||
/* This method is used to get a value. */
|
||||
void (*get_value_)(struct __vpiHandle*expr, s_vpi_value*vp);
|
||||
|
||||
/* This is a value union, that reflect state or the value of a
|
||||
handle. */
|
||||
union {
|
||||
unsigned unum;
|
||||
struct vvm_bits_t*bits;
|
||||
struct t_vpi_time time;
|
||||
} val;
|
||||
};
|
||||
|
||||
|
||||
/* TYPE MEANINGS:
|
||||
*
|
||||
* vpiArgument
|
||||
* This type of handle contains a single referent, the item that has
|
||||
* many arguments. It is an iterator.
|
||||
*
|
||||
* vpiConstant
|
||||
* Constant values, such as strings and numbers, are this type.
|
||||
*
|
||||
* vpiSysTaskCall
|
||||
* This handle type represents a call to a system task. It has a
|
||||
* to-many reference to argument expressions, and a to-one reference
|
||||
* to a vpiUserSystf object.
|
||||
*
|
||||
* vpiTimeVar
|
||||
* This type is a special kind of variable, that holds a time. The
|
||||
* time value is a more complex structure then a single number. The
|
||||
* type really seems to exist to implement the $time system variable.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $Log: vpi_priv.h,v $
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -19,7 +19,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm.h,v 1.9 1999/06/21 01:02:34 steve Exp $"
|
||||
#ident "$Id: vvm.h,v 1.14 1999/10/06 01:28:18 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <vector>
|
||||
@@ -80,6 +80,15 @@ inline vvm_bit_t less_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
|
||||
return c;
|
||||
}
|
||||
|
||||
inline vvm_bit_t greater_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
|
||||
{
|
||||
if (l == Vx) return Vx;
|
||||
if (r == Vx) return Vx;
|
||||
if (l > r) return V1;
|
||||
if (l < r) return V0;
|
||||
return c;
|
||||
}
|
||||
|
||||
extern vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry);
|
||||
|
||||
inline vvm_bit_t not(vvm_bit_t l)
|
||||
@@ -117,6 +126,18 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
|
||||
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
bits_[idx] = Vz;
|
||||
}
|
||||
vvm_bitset_t(const vvm_bitset_t<WIDTH>&that)
|
||||
{ bits_ = that.bits_; }
|
||||
vvm_bitset_t(const vvm_bits_t&that)
|
||||
{ unsigned wid = WIDTH;
|
||||
if (that.get_width() < WIDTH)
|
||||
wid = that.get_width();
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
bits_[idx] = that.get_bit(idx);
|
||||
for (unsigned idx = wid ; idx < WIDTH ; idx += 1)
|
||||
bits_[idx] = V0;
|
||||
}
|
||||
|
||||
|
||||
vvm_bit_t operator[] (unsigned idx) const { return bits_[idx]; }
|
||||
vvm_bit_t&operator[] (unsigned idx) { return bits_[idx]; }
|
||||
@@ -124,13 +145,6 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
|
||||
unsigned get_width() const { return WIDTH; }
|
||||
vvm_bit_t get_bit(unsigned idx) const { return bits_[idx]; }
|
||||
|
||||
bool eequal(const vvm_bitset_t<WIDTH>&that) const
|
||||
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
|
||||
if (bits_[idx] != that.bits_[idx])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned as_unsigned() const
|
||||
{ unsigned result = 0;
|
||||
for (unsigned idx = WIDTH ; idx > 0 ; idx -= 1) {
|
||||
@@ -140,6 +154,12 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
|
||||
return result;
|
||||
}
|
||||
|
||||
vvm_bitset_t<WIDTH>& operator= (const vvm_bitset_t<WIDTH>&that)
|
||||
{ if (this == &that) return *this;
|
||||
bits_ = that.bits_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
vvm_bit_t bits_[WIDTH];
|
||||
};
|
||||
@@ -207,7 +227,11 @@ class vvm_simulation {
|
||||
|
||||
unsigned long get_sim_time() const { return time_; }
|
||||
|
||||
// The s_finish() method marks the simulation as finished and
|
||||
// prevents more events being executed. The finished() method
|
||||
// returns true if the s_finish() method has been called.
|
||||
void s_finish();
|
||||
bool finished() const;
|
||||
|
||||
private:
|
||||
bool going_;
|
||||
@@ -235,17 +259,17 @@ class vvm_simulation {
|
||||
*/
|
||||
class vvm_monitor_t {
|
||||
public:
|
||||
vvm_monitor_t(const string&);
|
||||
vvm_monitor_t(const char*);
|
||||
|
||||
void trigger(vvm_simulation*sim)
|
||||
{ if (event_) sim->monitor_event(event_); }
|
||||
|
||||
const string& name() const { return name_; }
|
||||
const char* name() const { return name_; }
|
||||
|
||||
void enable(vvm_event*e) { event_ = e; }
|
||||
|
||||
private:
|
||||
string name_;
|
||||
const char* name_;
|
||||
vvm_event*event_;
|
||||
|
||||
private: // not implemented
|
||||
@@ -257,7 +281,7 @@ class vvm_monitor_t {
|
||||
template <unsigned WIDTH> class vvm_signal_t : public vvm_monitor_t {
|
||||
|
||||
public:
|
||||
vvm_signal_t(const string&n, vvm_bitset_t<WIDTH>*b)
|
||||
vvm_signal_t(const char*n, vvm_bitset_t<WIDTH>*b)
|
||||
: vvm_monitor_t(n), bits_(b)
|
||||
{ }
|
||||
|
||||
@@ -280,6 +304,21 @@ template <unsigned WIDTH> class vvm_signal_t : public vvm_monitor_t {
|
||||
|
||||
/*
|
||||
* $Log: vvm.h,v $
|
||||
* Revision 1.14 1999/10/06 01:28:18 steve
|
||||
* The $finish task should work immediately.
|
||||
*
|
||||
* Revision 1.13 1999/10/05 04:02:10 steve
|
||||
* Relaxed width handling for <= assignment.
|
||||
*
|
||||
* Revision 1.12 1999/09/29 18:36:04 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.11 1999/09/28 01:13:15 steve
|
||||
* Support in vvm > and >= behavioral operators.
|
||||
*
|
||||
* Revision 1.10 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
* Revision 1.9 1999/06/21 01:02:34 steve
|
||||
* Add init to vvm_signal_t.
|
||||
*
|
||||
|
||||
+480
-128
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -17,153 +17,505 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_calltf.cc,v 1.2 1999/05/31 15:46:36 steve Exp $"
|
||||
#ident "$Id: vvm_calltf.cc,v 1.6 1999/09/29 01:41:18 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm_calltf.h"
|
||||
# include <vpi_user.h>
|
||||
# include "vpi_priv.h"
|
||||
# include <new>
|
||||
# include <iostream>
|
||||
# include <assert.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdarg.h>
|
||||
# include <malloc.h>
|
||||
# include <stdio.h>
|
||||
# include <dlfcn.h>
|
||||
|
||||
vvm_calltf_parm::vvm_calltf_parm()
|
||||
: type_(NONE)
|
||||
{
|
||||
}
|
||||
# define MAX_PATHLEN 1024
|
||||
|
||||
vvm_calltf_parm::vvm_calltf_parm(TYPE t)
|
||||
: type_(t)
|
||||
{
|
||||
assert((t == NONE) || (t == TIME));
|
||||
}
|
||||
/* This simulation pointer is used by vpi functions to get back to the
|
||||
simulation. */
|
||||
static vvm_simulation*vpi_sim;
|
||||
|
||||
void vvm_calltf_parm::release_()
|
||||
{
|
||||
switch (type_) {
|
||||
case NONE:
|
||||
case TIME:
|
||||
case ULONG:
|
||||
break;
|
||||
case STRING:
|
||||
((string*)string_)->string::~string();
|
||||
break;
|
||||
case BITS:
|
||||
break;
|
||||
}
|
||||
type_ = NONE;
|
||||
}
|
||||
static vpiHandle vvm_vpi_cur_task;
|
||||
|
||||
vvm_calltf_parm& vvm_calltf_parm::operator= (unsigned long val)
|
||||
{
|
||||
release_();
|
||||
type_ = ULONG;
|
||||
ulong_ = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vvm_calltf_parm& vvm_calltf_parm::operator= (const string&val)
|
||||
{
|
||||
release_();
|
||||
type_ = STRING;
|
||||
new (string_) string (val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm::SIG&val)
|
||||
{
|
||||
release_();
|
||||
type_ = BITS;
|
||||
bits_ = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm&that)
|
||||
{
|
||||
if (this == &that)
|
||||
return *this;
|
||||
|
||||
release_();
|
||||
switch (that.type_) {
|
||||
case NONE:
|
||||
case TIME:
|
||||
type_ = that.type_;
|
||||
break;
|
||||
case ULONG:
|
||||
type_ = ULONG;
|
||||
ulong_ = that.ulong_;
|
||||
break;
|
||||
case STRING:
|
||||
type_ = STRING;
|
||||
new (string_) string (that.as_string());
|
||||
break;
|
||||
case BITS:
|
||||
type_ = BITS;
|
||||
bits_ = that.bits_;
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
vvm_calltf_parm::~vvm_calltf_parm()
|
||||
{
|
||||
release_();
|
||||
}
|
||||
|
||||
extern void Sdisplay(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*parms);
|
||||
extern void Smonitor(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*parms);
|
||||
|
||||
static void Sfinish(vvm_simulation*sim, const string&,
|
||||
unsigned, class vvm_calltf_parm*)
|
||||
{
|
||||
sim->s_finish();
|
||||
}
|
||||
|
||||
static struct {
|
||||
const string name;
|
||||
void (*func)(vvm_simulation*, const string&,
|
||||
unsigned, class vvm_calltf_parm*);
|
||||
} sys_table[] = {
|
||||
{ "$display", &Sdisplay },
|
||||
{ "$finish", &Sfinish },
|
||||
{ "$monitor", &Smonitor },
|
||||
{ "", 0 }
|
||||
/*
|
||||
* Keep a list of vpi_systf_data structures. This list is searched
|
||||
* forward whenever a function is invoked by name, and items are
|
||||
* pushed in front of the list whenever they are registered. This
|
||||
* allows entries to override older entries.
|
||||
*/
|
||||
struct systf_entry {
|
||||
struct systf_entry* next;
|
||||
s_vpi_systf_data systf_data;
|
||||
};
|
||||
|
||||
void vvm_calltask(vvm_simulation*sim, const string&fname,
|
||||
unsigned nparms, class vvm_calltf_parm*parms)
|
||||
static struct systf_entry*systf_list = 0;
|
||||
|
||||
extern "C" void vpi_register_systf(const struct t_vpi_systf_data*systf)
|
||||
{
|
||||
struct systf_entry*cur = new struct systf_entry;
|
||||
cur->systf_data = *systf;
|
||||
cur->systf_data.tfname = strdup(systf->tfname);
|
||||
cur->next = systf_list;
|
||||
systf_list = cur;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; sys_table[idx].func ; idx += 1)
|
||||
if (fname == sys_table[idx].name) {
|
||||
sys_table[idx].func(sim, fname, nparms, parms);
|
||||
return;
|
||||
}
|
||||
extern "C" void vpi_printf(const char*fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
cout << "Call " << fname << "(";
|
||||
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
|
||||
if (idx > 0) cout << ", ";
|
||||
switch (parms[idx].type()) {
|
||||
case vvm_calltf_parm::NONE:
|
||||
break;
|
||||
case vvm_calltf_parm::ULONG:
|
||||
cout << parms[idx].as_ulong();
|
||||
break;
|
||||
case vvm_calltf_parm::STRING:
|
||||
cout << "\"" << parms[idx].as_string() << "\"";
|
||||
break;
|
||||
case vvm_calltf_parm::BITS:
|
||||
cout << *parms[idx].as_bits();
|
||||
break;
|
||||
case vvm_calltf_parm::TIME:
|
||||
break;
|
||||
}
|
||||
extern "C" void vpi_sim_control(int func, ...)
|
||||
{
|
||||
switch (func) {
|
||||
case vpiFinish:
|
||||
vpi_sim->s_finish();
|
||||
break;
|
||||
}
|
||||
cout << ")" << endl;
|
||||
}
|
||||
|
||||
extern "C" vpiHandle vpi_handle(int type, vpiHandle ref)
|
||||
{
|
||||
switch (type) {
|
||||
case vpiSysTfCall:
|
||||
return vvm_vpi_cur_task;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" vpiHandle vpi_iterate(int type, vpiHandle ref)
|
||||
{
|
||||
vpiHandle res = (vpiHandle)calloc(1, sizeof (struct __vpiHandle));
|
||||
res->type = type;
|
||||
res->referent = ref;
|
||||
res->val.unum = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" vpiHandle vpi_scan(vpiHandle ref)
|
||||
{
|
||||
assert(ref->type == vpiArgument);
|
||||
if (ref->val.unum >= ref->referent->narguments) {
|
||||
vpi_free_object(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ref->referent->arguments[ref->val.unum++];
|
||||
}
|
||||
|
||||
extern "C" int vpi_get(int property, vpiHandle ref)
|
||||
{
|
||||
if (property == vpiType)
|
||||
return ref->type;
|
||||
|
||||
if (ref->get_ == 0)
|
||||
return -1;
|
||||
|
||||
return (ref->get_)(property, ref);
|
||||
}
|
||||
|
||||
extern "C" char* vpi_get_str(int property, vpiHandle ref)
|
||||
{
|
||||
if (property == vpiFullName)
|
||||
return ref->full_name;
|
||||
|
||||
if (ref->get_str_ == 0)
|
||||
return 0;
|
||||
|
||||
return (ref->get_str_)(property, ref);
|
||||
|
||||
switch (property) {
|
||||
case vpiName:
|
||||
return ref->full_name;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
|
||||
{
|
||||
if (expr->get_value_) {
|
||||
expr->get_value_(expr, vp);
|
||||
return;
|
||||
}
|
||||
|
||||
vp->format = vpiSuppressVal;
|
||||
}
|
||||
|
||||
extern "C" int vpi_free_object(vpiHandle ref)
|
||||
{
|
||||
free(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is a get_value_ method of a vpiHandle, that supports
|
||||
* reading bits as a string.
|
||||
*/
|
||||
static void get_value_bits(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
static char buff[1024];
|
||||
char*cp;
|
||||
unsigned width, bytes;
|
||||
unsigned val;
|
||||
assert(ref->val.bits);
|
||||
width = ref->val.bits->get_width();
|
||||
cp = buff;
|
||||
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiBinStrVal:
|
||||
for (unsigned idx = 0 ; idx < width ; idx += 1)
|
||||
switch (ref->val.bits->get_bit(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 (unsigned idx = 0 ; idx < width ; idx += 1) {
|
||||
val *= 2;
|
||||
switch (ref->val.bits->get_bit(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:
|
||||
bytes = width%3;
|
||||
if (bytes) {
|
||||
*cp++ = '?';
|
||||
}
|
||||
for (unsigned idx = bytes ; idx < width ; idx += 3) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
for (unsigned i = idx ; i < idx+3 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (ref->val.bits->get_bit(width-idx-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;
|
||||
for (unsigned i = 0 ; i < width%4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (ref->val.bits->get_bit(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 (unsigned idx = width%4 ; idx < width ; idx += 4) {
|
||||
unsigned x = 0;
|
||||
unsigned z = 0;
|
||||
unsigned v = 0;
|
||||
for (unsigned i = idx ; i < idx+4 ; i += 1) {
|
||||
v *= 2;
|
||||
switch (ref->val.bits->get_bit(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;
|
||||
}
|
||||
|
||||
static void get_value_strconst(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiStringVal:
|
||||
vp->value.str = ref->full_name;
|
||||
vp->format = vpiStringVal;
|
||||
break;
|
||||
|
||||
default:
|
||||
vp->format = vpiSuppressVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_value_timevar(vpiHandle ref, s_vpi_value*vp)
|
||||
{
|
||||
static char buf[128];
|
||||
switch (vp->format) {
|
||||
case vpiObjTypeVal:
|
||||
case vpiTimeVal:
|
||||
vp->value.time = &ref->val.time;
|
||||
vp->format = vpiTimeVal;
|
||||
break;
|
||||
|
||||
case vpiDecStrVal:
|
||||
sprintf(buf, "%u", ref->val.time.low);
|
||||
vp->value.str = buf;
|
||||
break;
|
||||
|
||||
default:
|
||||
vp->format = vpiSuppressVal;
|
||||
vp->value.str = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The load_vpi_module function attempts to locate and load the named
|
||||
* vpi module and call the included startup routines. This is invoked
|
||||
* by the generated C++ code to load all the modules that the
|
||||
* simulation requires.
|
||||
*
|
||||
* If there is a '/' character in the name, or there is no
|
||||
* VPI_MODULE_PATH, the the name is usd as is. No path is searched for
|
||||
* the module.
|
||||
*
|
||||
* If there is a VPI_MODULE_PATH and there is no '/' in the name, the
|
||||
* VPI_MODULE_PATH is taken as a ':' separated list of directory
|
||||
* names. Each directory is searched for a module with the right name
|
||||
* that will link in. The current working directory is not implicitly
|
||||
* tried. If you wish '.' be in th search path, include it.
|
||||
*/
|
||||
typedef void (*vlog_startup_routines_t)(void);
|
||||
|
||||
void vvm_load_vpi_module(const char*name)
|
||||
{
|
||||
void*mod = 0;
|
||||
const char*path = getenv("VPI_MODULE_PATH");
|
||||
|
||||
if ((path == 0) || (strchr(name, '/'))) {
|
||||
mod = dlopen(name, RTLD_NOW);
|
||||
if (mod == 0) {
|
||||
cerr << name << ": " << dlerror() << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
const char*cur = path;
|
||||
const char*ep;
|
||||
for (cur = path ; cur ; cur = ep? ep+1 : 0) {
|
||||
char dest[MAX_PATHLEN+1];
|
||||
|
||||
ep = strchr(cur, ':');
|
||||
size_t n = ep? ep-cur : strlen(cur);
|
||||
if ((n + strlen(name) + 2) > sizeof dest)
|
||||
continue;
|
||||
|
||||
strncpy(dest, cur, n);
|
||||
dest[n] = '/';
|
||||
dest[n+1] = 0;
|
||||
strcat(dest, name);
|
||||
|
||||
mod = dlopen(dest, RTLD_NOW);
|
||||
if (mod) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mod == 0) {
|
||||
cerr << dlerror() << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
void*table = dlsym(mod, "vlog_startup_routines");
|
||||
vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table;
|
||||
if (routines == 0) {
|
||||
cerr << name << ": Unable to locate the vlog_startup_routines"
|
||||
" table." << endl;
|
||||
dlclose(mod);
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; routines[idx] ; idx += 1)
|
||||
(routines[idx])();
|
||||
}
|
||||
|
||||
void vvm_make_vpi_parm(vpiHandle ref, const char*val)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = vpiConstant;
|
||||
ref->subtype = vpiStringConst;
|
||||
ref->full_name = const_cast<char*>(val);
|
||||
ref->get_value_ = &get_value_strconst;
|
||||
}
|
||||
|
||||
void vvm_make_vpi_parm(vpiHandle ref, vvm_bits_t*val)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = vpiConstant;
|
||||
ref->subtype = vpiBinaryConst;
|
||||
ref->full_name = "";
|
||||
ref->val.bits = val;
|
||||
ref->get_value_ = &get_value_bits;
|
||||
}
|
||||
|
||||
void vvm_init_vpi_handle(vpiHandle ref, vvm_bits_t*bits, vvm_monitor_t*mon)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = vpiReg;
|
||||
ref->full_name = const_cast<char*>(mon->name());
|
||||
ref->val.bits = bits;
|
||||
ref->get_value_ = &get_value_bits;
|
||||
}
|
||||
|
||||
void vvm_init_vpi_timevar(vpiHandle ref, const char*name)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = vpiTimeVar;
|
||||
ref->full_name = const_cast<char*>(name);
|
||||
ref->get_value_ = &get_value_timevar;
|
||||
}
|
||||
|
||||
void vvm_make_vpi_parm(vpiHandle ref)
|
||||
{
|
||||
memset(ref, 0, sizeof*ref);
|
||||
ref->type = 0;
|
||||
}
|
||||
|
||||
void vvm_calltask(vvm_simulation*sim, const string&fname,
|
||||
unsigned nparms, vpiHandle*parms)
|
||||
{
|
||||
vpi_sim = sim;
|
||||
|
||||
struct __vpiHandle cur_task;
|
||||
cur_task.type = vpiSysTaskCall;
|
||||
cur_task.full_name = 0;
|
||||
cur_task.referent = 0;
|
||||
cur_task.arguments = parms;
|
||||
cur_task.narguments = nparms;
|
||||
|
||||
vvm_vpi_cur_task = &cur_task;
|
||||
|
||||
/* Look for a systf function to invoke. */
|
||||
for (systf_entry*idx = systf_list ; idx ; idx = idx->next)
|
||||
if (fname == idx->systf_data.tfname) {
|
||||
cur_task.full_name = idx->systf_data.tfname;
|
||||
idx->systf_data.calltf(idx->systf_data.user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Finally, if nothing is found then something is not
|
||||
right. Print out the function name all the parameters
|
||||
passed, so that someone can deal with it. */
|
||||
cout << "Call " << fname << endl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: vvm_calltf.cc,v $
|
||||
* Revision 1.6 1999/09/29 01:41:18 steve
|
||||
* Support the $write system task, and have the
|
||||
* vpi_scan function free iterators as needed.
|
||||
*
|
||||
* Revision 1.5 1999/09/13 03:08:10 steve
|
||||
* fix vpiHexStrVal dumping of digits to strings.
|
||||
*
|
||||
* Revision 1.4 1999/08/19 02:51:11 steve
|
||||
* Add vpi_sim_control
|
||||
*
|
||||
* Revision 1.3 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
* Revision 1.2 1999/05/31 15:46:36 steve
|
||||
* Handle time in more places.
|
||||
*
|
||||
|
||||
+30
-48
@@ -19,69 +19,51 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_calltf.h,v 1.1 1998/11/09 23:44:11 steve Exp $"
|
||||
#ident "$Id: vvm_calltf.h,v 1.2 1999/08/15 01:23:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
# include <string>
|
||||
|
||||
typedef struct __vpiHandle*vpiHandle;
|
||||
|
||||
/*
|
||||
* This function loads a vpi module by name.
|
||||
*/
|
||||
extern void vvm_load_vpi_module(const char*path);
|
||||
|
||||
|
||||
/*
|
||||
* The vvm_init_vpi_handle functions initialize statis VPI handles
|
||||
* that may be used many places within the program.
|
||||
*/
|
||||
extern void vvm_init_vpi_handle(vpiHandle, vvm_bits_t*, vvm_monitor_t*);
|
||||
extern void vvm_init_vpi_timevar(vpiHandle, const char*name);
|
||||
|
||||
/*
|
||||
* The vvm_make_vpi_parm functions initialize the vpiHandles to
|
||||
* represent objects suitable for use as vvm_calltask parameters.
|
||||
*/
|
||||
extern void vvm_make_vpi_parm(vpiHandle ref, const char*val);
|
||||
extern void vvm_make_vpi_parm(vpiHandle ref, vvm_bits_t*val);
|
||||
extern void vvm_make_vpi_parm(vpiHandle ref);
|
||||
|
||||
/*
|
||||
* The vvm environment supports external calls to C++ by
|
||||
* vvm_calltask. The code generator generates calls to vvm_calltask
|
||||
* that corresponds to the system call in the Verilog source. The
|
||||
* vvm_calltask in turn locates the function (by name) and calls the
|
||||
* C++ code that implements the task.
|
||||
*
|
||||
* The parameters of the task are implemented as an array of
|
||||
* vvm_calltf_parm objects. Each object represents a paramter from the
|
||||
* source.
|
||||
* vvm_calltask in turn locates the vpi implementation (by name) and
|
||||
* calls the VPI that implements the task.
|
||||
*/
|
||||
class vvm_calltf_parm {
|
||||
|
||||
public:
|
||||
enum TYPE { NONE, ULONG, STRING, BITS, TIME };
|
||||
|
||||
vvm_calltf_parm();
|
||||
explicit vvm_calltf_parm(TYPE);
|
||||
vvm_calltf_parm(const vvm_calltf_parm&);
|
||||
~vvm_calltf_parm();
|
||||
|
||||
TYPE type() const { return type_; }
|
||||
|
||||
struct SIG {
|
||||
vvm_bits_t*bits;
|
||||
vvm_monitor_t*mon;
|
||||
};
|
||||
|
||||
unsigned long as_ulong() const { return ulong_; }
|
||||
string as_string() const { return *(string*)string_; }
|
||||
vvm_bits_t* as_bits() const { return bits_.bits; }
|
||||
vvm_monitor_t* as_mon() const { return bits_.mon; }
|
||||
|
||||
const string& sig_name() const { return bits_.mon->name(); }
|
||||
|
||||
vvm_calltf_parm& operator= (unsigned long);
|
||||
vvm_calltf_parm& operator= (const string&);
|
||||
vvm_calltf_parm& operator= (const SIG&);
|
||||
vvm_calltf_parm& operator= (const vvm_calltf_parm&);
|
||||
|
||||
private:
|
||||
TYPE type_;
|
||||
|
||||
union {
|
||||
unsigned long ulong_;
|
||||
char string_[sizeof(string)];
|
||||
SIG bits_;
|
||||
};
|
||||
|
||||
void release_();
|
||||
};
|
||||
|
||||
extern void vvm_calltask(vvm_simulation*sim, const string&name,
|
||||
unsigned nparms, class vvm_calltf_parm*parms);
|
||||
unsigned nparms, vpiHandle*parms);
|
||||
|
||||
/*
|
||||
* $Log: vvm_calltf.h,v $
|
||||
* Revision 1.2 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
* Revision 1.1 1998/11/09 23:44:11 steve
|
||||
* Add vvm library.
|
||||
*
|
||||
|
||||
+302
-3
@@ -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.7 1999/06/24 04:20:47 steve Exp $"
|
||||
#ident "$Id: vvm_func.h,v 1.14 1999/10/05 06:19:47 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
@@ -78,6 +78,13 @@ vvm_bitset_t<1> vvm_unop_or(const vvm_bitset_t<WIDTH>&r)
|
||||
return res;
|
||||
}
|
||||
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<1> vvm_unop_nor(const vvm_bitset_t<WIDTH>&r)
|
||||
{
|
||||
vvm_bitset_t<1>res = vvm_unop_or(r);
|
||||
return vvm_unop_not(res);
|
||||
}
|
||||
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<1> vvm_unop_lnot(const vvm_bitset_t<WIDTH>&r)
|
||||
{
|
||||
@@ -85,6 +92,44 @@ vvm_bitset_t<1> vvm_unop_lnot(const vvm_bitset_t<WIDTH>&r)
|
||||
return vvm_unop_not(res);
|
||||
}
|
||||
|
||||
/*
|
||||
* The unary XOR is the reduction XOR. It returns a single bit.
|
||||
*/
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<1> vvm_unop_xor(const vvm_bitset_t<WIDTH>&r)
|
||||
{
|
||||
vvm_bitset_t<1> res;
|
||||
res[0] = V0;
|
||||
|
||||
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
|
||||
if (r[idx] == V1)
|
||||
res[0] = not(res[0]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<1> vvm_unop_xnor(const vvm_bitset_t<WIDTH>&r)
|
||||
{
|
||||
return not(vvm_unop_xor(r));
|
||||
}
|
||||
|
||||
//
|
||||
// simple-minded unary minus operator (two's complement)
|
||||
//
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<WIDTH> vvm_unop_uminus(const vvm_bitset_t<WIDTH>&l)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> res;
|
||||
res = vvm_unop_not(l);
|
||||
vvm_bit_t carry = V1;
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
res[i] = add_with_carry(res[i], V0, carry);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the binary AND operator. This is a bitwise and with all
|
||||
* the parameters and the result having the same width.
|
||||
@@ -165,6 +210,40 @@ vvm_bitset_t<WIDTH> vvm_binop_xor(const vvm_bitset_t<WIDTH>&l,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* the binary 'l' operator is a logic left-shift by the number of positions
|
||||
* indicated by argument r. r is an unsigned integer, which is represented
|
||||
* internally as a 32-bit bitvector.
|
||||
*/
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<WIDTH> vvm_binop_shiftl(const vvm_bitset_t<WIDTH>&l,
|
||||
const vvm_bitset_t<32>&r)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> result;
|
||||
vvm_u32 s = r.as_unsigned();
|
||||
for (unsigned idx = 0; idx < WIDTH; idx++)
|
||||
result[idx] = (idx < s) ? V0 : l[idx-s];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The binary 'r' operator is a logic right-shift by the number of positions
|
||||
* indicated by argument r. r is an unsigned integer, which is represented
|
||||
* internally by a 32-bit bitvector.
|
||||
*/
|
||||
template <unsigned WIDTH>
|
||||
vvm_bitset_t<WIDTH> vvm_binop_shiftr(const vvm_bitset_t<WIDTH>&l,
|
||||
const vvm_bitset_t<32>&r)
|
||||
{
|
||||
vvm_bitset_t<WIDTH> result;
|
||||
vvm_u32 s = r.as_unsigned();
|
||||
for (unsigned idx = 0; idx < WIDTH; idx++)
|
||||
result[idx] = (idx < (WIDTH-s)) ? l[idx+s] : V0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for equality are a bit tricky, as they allow for the left and
|
||||
* right subexpressions to have different size. The shorter bitset is
|
||||
@@ -239,6 +318,10 @@ vvm_bitset_t<1> vvm_binop_eq(const vvm_bitset_t<LW>&l,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function return true if all the bits are the same. Even x and
|
||||
* z bites are compared for equality.
|
||||
*/
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_eeq(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
@@ -277,6 +360,112 @@ vvm_bitset_t<1> vvm_binop_eeq(const vvm_bitset_t<LW>&l,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function return true if all the bits are the same. The x and z
|
||||
* bits are don't care, s don't make the result false.
|
||||
*/
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_xeq(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V1;
|
||||
|
||||
if (LW <= RW) {
|
||||
for (unsigned idx = 0 ; idx < LW ; idx += 1) {
|
||||
if ((l[idx] == Vz) || (r[idx] == Vz))
|
||||
continue;
|
||||
if ((l[idx] == Vx) || (r[idx] == Vx))
|
||||
continue;
|
||||
if (l[idx] != r[idx]) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1) {
|
||||
if ((r[idx] == Vx) || (r[idx] == Vz))
|
||||
continue;
|
||||
if (r[idx] != V0) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (unsigned idx = 0 ; idx < RW ; idx += 1) {
|
||||
if ((l[idx] == Vz) || (r[idx] == Vz))
|
||||
continue;
|
||||
if ((l[idx] == Vx) || (r[idx] == Vx))
|
||||
continue;
|
||||
if (l[idx] != r[idx]) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1) {
|
||||
if ((l[idx] == Vx) || (l[idx] == Vz))
|
||||
continue;
|
||||
if (l[idx] != V0) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function return true if all the bits are the same. The z
|
||||
* bits are don't care, so don't make the result false.
|
||||
*/
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_zeq(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V1;
|
||||
|
||||
if (LW <= RW) {
|
||||
for (unsigned idx = 0 ; idx < LW ; idx += 1) {
|
||||
if ((l[idx] == Vz) || (r[idx] == Vz))
|
||||
continue;
|
||||
if (l[idx] != r[idx]) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1) {
|
||||
if (r[idx] == Vz)
|
||||
continue;
|
||||
if (r[idx] != V0) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (unsigned idx = 0 ; idx < RW ; idx += 1) {
|
||||
if ((l[idx] == Vz) || (r[idx] == Vz))
|
||||
continue;
|
||||
if (l[idx] != r[idx]) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1) {
|
||||
if (l[idx] == Vz)
|
||||
continue;
|
||||
if (l[idx] != V0) {
|
||||
result[0] = V0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_ne(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
@@ -299,12 +488,87 @@ template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_lt(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
assert(LW == RW);
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V0;
|
||||
for (unsigned idx = 0 ; idx < LW ; idx += 1)
|
||||
const unsigned common = (LW < RW)? LW : RW;
|
||||
for (unsigned idx = 0 ; idx < common ; idx += 1)
|
||||
result[0] = less_with_cascade(l[idx], r[idx], result[0]);
|
||||
|
||||
if (LW > RW) {
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1)
|
||||
result[0] = less_with_cascade(l[idx], V0, result[0]);
|
||||
} else {
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1)
|
||||
result[0] = less_with_cascade(V0, r[idx], result[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The <= operator takes operands of natural width and returns a
|
||||
* single bit. The result is V1 if l <= r, otherwise V0;
|
||||
*/
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_le(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V1;
|
||||
const unsigned common = (LW < RW)? LW : RW;
|
||||
for (unsigned idx = 0 ; idx < common ; idx += 1)
|
||||
result[0] = less_with_cascade(l[idx], r[idx], result[0]);
|
||||
|
||||
if (LW > RW) {
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1)
|
||||
result[0] = less_with_cascade(l[idx], V0, result[0]);
|
||||
} else {
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1)
|
||||
result[0] = less_with_cascade(V0, r[idx], result[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_gt(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V0;
|
||||
const unsigned common = (LW < RW)? LW : RW;
|
||||
for (unsigned idx = 0 ; idx < common ; idx += 1)
|
||||
result[0] = greater_with_cascade(l[idx], r[idx], result[0]);
|
||||
|
||||
if (LW > RW) {
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1)
|
||||
result[0] = greater_with_cascade(l[idx], V0, result[0]);
|
||||
} else {
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1)
|
||||
result[0] = greater_with_cascade(V0, r[idx], result[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <unsigned LW, unsigned RW>
|
||||
vvm_bitset_t<1> vvm_binop_ge(const vvm_bitset_t<LW>&l,
|
||||
const vvm_bitset_t<RW>&r)
|
||||
{
|
||||
vvm_bitset_t<1> result;
|
||||
result[0] = V1;
|
||||
const unsigned common = (LW < RW)? LW : RW;
|
||||
for (unsigned idx = 0 ; idx < common ; idx += 1)
|
||||
result[0] = greater_with_cascade(l[idx], r[idx], result[0]);
|
||||
|
||||
if (LW > RW) {
|
||||
for (unsigned idx = RW ; idx < LW ; idx += 1)
|
||||
result[0] = greater_with_cascade(l[idx], V0, result[0]);
|
||||
} else {
|
||||
for (unsigned idx = LW ; idx < RW ; idx += 1)
|
||||
result[0] = greater_with_cascade(V0, r[idx], result[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -328,8 +592,43 @@ vvm_bitset_t<1> vvm_binop_lor(const vvm_bitset_t<LW>&l,
|
||||
return res1;
|
||||
}
|
||||
|
||||
template <unsigned W>
|
||||
vvm_bitset_t<W> vvm_ternary(vvm_bit_t c, const vvm_bitset_t<W>&t,
|
||||
const vvm_bitset_t<W>&f)
|
||||
{
|
||||
switch (c) {
|
||||
case V0:
|
||||
return f;
|
||||
case V1:
|
||||
return t;
|
||||
default:
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: vvm_func.h,v $
|
||||
* Revision 1.14 1999/10/05 06:19:47 steve
|
||||
* Add support for reduction NOR.
|
||||
*
|
||||
* Revision 1.13 1999/10/01 15:26:29 steve
|
||||
* Add some vvm operators from Eric Aardoom.
|
||||
*
|
||||
* Revision 1.12 1999/09/29 22:57:26 steve
|
||||
* LT supports different width objects.
|
||||
*
|
||||
* Revision 1.11 1999/09/29 18:36:04 steve
|
||||
* Full case support
|
||||
*
|
||||
* Revision 1.10 1999/09/28 01:13:16 steve
|
||||
* Support in vvm > and >= behavioral operators.
|
||||
*
|
||||
* Revision 1.9 1999/09/23 04:39:52 steve
|
||||
* The <= operator takes different width operands.
|
||||
*
|
||||
* Revision 1.8 1999/09/11 04:43:17 steve
|
||||
* Support ternary and <= operators in vvm.
|
||||
*
|
||||
* Revision 1.7 1999/06/24 04:20:47 steve
|
||||
* Add !== and === operators.
|
||||
*
|
||||
|
||||
+5
-2
@@ -17,13 +17,13 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_monitor.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
|
||||
#ident "$Id: vvm_monitor.cc,v 1.2 1999/08/15 01:23:56 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
|
||||
|
||||
vvm_monitor_t::vvm_monitor_t(const string&n)
|
||||
vvm_monitor_t::vvm_monitor_t(const char*n)
|
||||
: name_(n)
|
||||
{
|
||||
}
|
||||
@@ -31,6 +31,9 @@ vvm_monitor_t::vvm_monitor_t(const string&n)
|
||||
|
||||
/*
|
||||
* $Log: vvm_monitor.cc,v $
|
||||
* Revision 1.2 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
* Revision 1.1 1998/11/09 23:44:11 steve
|
||||
* Add vvm library.
|
||||
*
|
||||
|
||||
+21
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vvm_simulation.cc,v 1.4 1999/06/19 03:31:33 steve Exp $"
|
||||
#ident "$Id: vvm_simulation.cc,v 1.6 1999/10/06 01:28:18 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvm.h"
|
||||
@@ -132,7 +132,7 @@ void vvm_simulation::run()
|
||||
time_ += sim_->delay;
|
||||
sim_->delay = 0;
|
||||
|
||||
for (;;) {
|
||||
while (going_) {
|
||||
/* Look for some events to make active. If the
|
||||
main event list is empty, then activate the
|
||||
nonblock list. */
|
||||
@@ -150,7 +150,7 @@ void vvm_simulation::run()
|
||||
if (active == 0)
|
||||
break;
|
||||
|
||||
while (active) {
|
||||
while (active && going_) {
|
||||
vvm_event*cur = active;
|
||||
active = cur->next_;
|
||||
cur->event_function();
|
||||
@@ -158,6 +158,12 @@ void vvm_simulation::run()
|
||||
}
|
||||
}
|
||||
|
||||
/* If the simulation was stopped by one of the events,
|
||||
then break out of the loop before doing any monitor
|
||||
events, and before clearing the current time. */
|
||||
if (!going_)
|
||||
break;
|
||||
|
||||
/* XXXX Execute monitor events here. */
|
||||
if (mon_) {
|
||||
mon_->event_function();
|
||||
@@ -193,9 +199,13 @@ void vvm_simulation::s_finish()
|
||||
going_ = false;
|
||||
}
|
||||
|
||||
bool vvm_simulation::finished() const
|
||||
{
|
||||
return !going_;
|
||||
}
|
||||
|
||||
void vvm_simulation::thread_delay(unsigned long delay, vvm_thread*thr)
|
||||
{
|
||||
assert(delay > 0);
|
||||
delay_event*ev = new delay_event(thr);
|
||||
insert_event(delay, ev);
|
||||
}
|
||||
@@ -209,6 +219,12 @@ void vvm_simulation::thread_active(vvm_thread*thr)
|
||||
|
||||
/*
|
||||
* $Log: vvm_simulation.cc,v $
|
||||
* Revision 1.6 1999/10/06 01:28:18 steve
|
||||
* The $finish task should work immediately.
|
||||
*
|
||||
* Revision 1.5 1999/09/29 02:53:33 steve
|
||||
* Useless assertion.
|
||||
*
|
||||
* Revision 1.4 1999/06/19 03:31:33 steve
|
||||
* End run if events run out.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
|
||||
For those of you who wish to use Icarus Verilog, in combination with
|
||||
the Xilinx back end (Foundation or Alliance), it can be done. I have
|
||||
run some admittedly simple (no arithmetic, 600 equivalent gates) designs
|
||||
through this setup, targeting a Spartan XCS10.
|
||||
|
||||
Verilog:
|
||||
|
||||
As of Icarus Verilog 19990814, you still can't have logic buried
|
||||
in procedural (flip-flop) assignment. I use a hacked workaround
|
||||
copy of ivl that allows 1-bit wide logic. The other approach
|
||||
is to use temporary wires, assign them to the logic, and assign
|
||||
the reg to that wire. For example, instead of
|
||||
always @ (posedge Clk) Z = ~Q1 & ~Q2 & ~Q3 & ~Q4;
|
||||
you can write
|
||||
wire newZ;
|
||||
assign newZ = ~Q1 & ~Q2 & ~Q3 & ~Q4;
|
||||
always @ (posedge Clk) Z = newZ;
|
||||
|
||||
Procedural assignments have to be given one at a time, to be
|
||||
"found" by xnfsyn. Say
|
||||
always @ (posedge Clk) Y = newY;
|
||||
always @ (posedge Clk) Z = newZ;
|
||||
rather than
|
||||
always @ (posedge Clk) begin
|
||||
Y = newY;
|
||||
Z = newZ;
|
||||
end
|
||||
|
||||
I had reason to use a global clock net. I used this snippet of
|
||||
Verilog code to make it happen:
|
||||
primitive BUFG ( O, I );
|
||||
output O;
|
||||
input I;
|
||||
table
|
||||
0:0;
|
||||
1:1;
|
||||
endtable
|
||||
endprimitive
|
||||
$attribute(BUFG,"XNF-LCA","BUFG:O,I")
|
||||
|
||||
Oh, yes, you probably also want to choose I/O pins! Try this:
|
||||
wire d1;
|
||||
$attribute(d1, "PAD", "i45"); // input
|
||||
wire vsync;
|
||||
$attribute(vsync, "PAD", "o67"); // output
|
||||
|
||||
Running ivl:
|
||||
|
||||
The -F switches are important. The following order seems to robustly
|
||||
generate valid XNF files:
|
||||
-Fxnfio -Fnobufz -Fsigfold -Fxnfsyn
|
||||
|
||||
Generating .pcf files:
|
||||
|
||||
The ngdbuild step seems to lose pin placement information that ivl
|
||||
puts in the XNF file. Use xnf2pcf to extract this information to
|
||||
a .pcf file, which the Xilinx place-and-route software _will_ pay
|
||||
attention to.
|
||||
|
||||
Running the Xilinx back end:
|
||||
|
||||
You can presumably use the GUI, but that doesn't fit in Makefiles :-).
|
||||
Here is the command sequence in pseudo-shell-script:
|
||||
ngdbuild -p $part $1.xnf $1.ngd
|
||||
map -p $part -o map.ncd $1.ngd
|
||||
xnf2pcf <$1.xnf >$1.pcf # see above
|
||||
par -w -ol 2 -d 0 map.ncd $1.ncd $1.pcf
|
||||
bitgen_flags = -g ConfigRate:SLOW -g TdoPin:PULLNONE -g DonePin:PULLUP \
|
||||
-g CRC:enable -g StartUpClk:CCLK -g SyncToDone:no \
|
||||
-g DoneActive:C1 -g OutputsActive:C3 -g GSRInactive:C4 \
|
||||
-g ReadClk:CCLK -g ReadCapture:enable -g ReadAbort:disable
|
||||
bitgen $1.ncd -l -w $bitgen_flags
|
||||
|
||||
The Xilinx software has diarrhea of the temp files (14, not including
|
||||
.xnf, .pcf, .ngd, .ncd, and .bit), so this sequence is best done in a
|
||||
dedicated directory. Note in particular that map.ncd is a generic name.
|
||||
|
||||
Downloading:
|
||||
|
||||
I use the XESS (http://www.xess.com/) XSP-10 development board, which
|
||||
uses the PC parallel (printer) port for downloading and interaction
|
||||
with the host. They made an old version of their download program
|
||||
public domain, posted it at
|
||||
http://www.xess.com/FPGA/xstools.zip ,
|
||||
and now there is a Linux port at
|
||||
ftp://ftp.microux.com/pub/pilotscope/xstools.tar.gz .
|
||||
|
||||
The above hints are based on my experience with Foundation 1.5 on NT
|
||||
(gack) and Alliance 2.1i on Solaris. Your mileage may vary. Good luck!
|
||||
|
||||
- Larry Doolittle <[email protected]> August 19, 1999
|
||||
@@ -22,7 +22,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 -Fxnfsyn -Fxnfio [...]
|
||||
ivl -txnf -fpart=4010e -Fxnfsyn -Fsigfold -Fxnfio [...]
|
||||
|
||||
Icarus Verilog includes the functions ``xnfsyn'' and ``xnfio'' to
|
||||
perform transformations and optimizations on the design before code is
|
||||
@@ -83,6 +83,9 @@ IBUF, NOT gates cannot be absorbed as in the OPAD case.
|
||||
|
||||
|
||||
$Log: xnf.txt,v $
|
||||
Revision 1.4 1999/08/14 22:48:21 steve
|
||||
Mention the sigfold function.
|
||||
|
||||
Revision 1.3 1999/07/22 02:05:20 steve
|
||||
is_constant method for PEConcat.
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
# xnf2pcf
|
||||
|
||||
# Converts perfectly good EXT records from an XNF file to
|
||||
# a .pcf file for the "par" step of the Xilinx toolchain.
|
||||
# Why on earth is this needed? Oh, well, the joys of working
|
||||
# with black-box-ware.
|
||||
|
||||
# Usage: xnf2pcf <design.xnf >design.pcf
|
||||
|
||||
# Refer to the resulting .pcf file in the invocation of "par", syntax:
|
||||
# par [options] infile[.ncd] outfile pcf_file[.pcf]
|
||||
|
||||
# Tested (successfully!) with XNF from Icarus Verilog, see
|
||||
# http://www.geda.seul.org/tools/verilog/index.html
|
||||
# and Xilinx back end tools from Foundation 1.5
|
||||
|
||||
# Author: Larry Doolittle <[email protected]>
|
||||
# Date: August 19, 1999
|
||||
|
||||
echo "SCHEMATIC START ;"
|
||||
echo "SCHEMATIC END ;"
|
||||
echo
|
||||
|
||||
awk '/^EXT/{gsub(",",""); printf("COMP \"%s\" LOCATE = SITE \"P%s\" ;\n", $2, $4)}'
|
||||
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: xnfsyn.cc,v 1.2 1999/07/18 21:17:51 steve Exp $"
|
||||
#ident "$Id: xnfsyn.cc,v 1.3 1999/08/18 04:00:02 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -136,13 +136,16 @@ void xnfsyn_f::proc_casn_(class Design*des)
|
||||
|
||||
// ... and the rval must be a simple signal.
|
||||
NetESignal*sig = dynamic_cast<NetESignal*>(asn_->rval());
|
||||
if (sig == 0)
|
||||
if (sig == 0) {
|
||||
cerr << "Noted complex rval in DFF, name " << asn_->name() <<
|
||||
", not yet implemented" << endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// The signal and the assignment must be the same width...
|
||||
assert(asn_->pin_count() == sig->pin_count());
|
||||
|
||||
// Geneate enough DFF objects to handle the entire width.
|
||||
// Generate enough DFF objects to handle the entire width.
|
||||
for (unsigned idx = 0 ; idx < asn_->pin_count() ; idx += 1) {
|
||||
|
||||
// XXXX FIXME: Objects need unique names!
|
||||
@@ -170,7 +173,7 @@ void xnfsyn_f::proc_casn_(class Design*des)
|
||||
}
|
||||
|
||||
/*
|
||||
* The process si far has been matches as:
|
||||
* The process so far has been matched as:
|
||||
*
|
||||
* always @(posedge nclk_) if ...;
|
||||
* always @(negedge nclk_) if ...;
|
||||
@@ -197,7 +200,7 @@ void xnfsyn_f::proc_ccon_(class Design*des)
|
||||
if (ce->pin_count() != 1)
|
||||
return;
|
||||
|
||||
// Geneate enough DFF objects to handle the entire width.
|
||||
// Generate enough DFF objects to handle the entire width.
|
||||
for (unsigned idx = 0 ; idx < asn_->pin_count() ; idx += 1) {
|
||||
|
||||
// XXXX FIXME: Objects need unique names!
|
||||
@@ -233,6 +236,9 @@ void xnfsyn(Design*des)
|
||||
|
||||
/*
|
||||
* $Log: xnfsyn.cc,v $
|
||||
* Revision 1.3 1999/08/18 04:00:02 steve
|
||||
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
|
||||
*
|
||||
* Revision 1.2 1999/07/18 21:17:51 steve
|
||||
* Add support for CE input to XNF DFF, and do
|
||||
* complete cleanup of replaced design nodes.
|
||||
|
||||
Reference in New Issue
Block a user