Compare commits

..
1 Commits
Author SHA1 Message Date
steve e67952240b Installation fixes for Debian. 1999-12-03 17:43:49 +00:00
193 changed files with 9592 additions and 30812 deletions
-5
View File
@@ -1,17 +1,12 @@
lexor_keyword.cc
parse.h
parse.cc
parse.cc.output
syn-rules.cc
syn-rules.cc.output
lexor.cc
ivl
dep
configure
Makefile
verilog
gverilog
iverilog
config.status
config.log
config.cache
+2 -5
View File
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: LineInfo.h,v 1.4 2000/02/23 02:56:53 steve Exp $"
#if !defined(WINNT)
#ident "$Id: LineInfo.h,v 1.3 1999/02/15 02:06:15 steve Exp $"
#endif
# include <cstdio>
@@ -50,9 +50,6 @@ class LineInfo {
/*
* $Log: LineInfo.h,v $
* Revision 1.4 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/02/15 02:06:15 steve
* Elaborate gate ranges.
*
+31 -61
View File
@@ -18,12 +18,12 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.73 2000/10/08 22:36:55 steve Exp $"
#ident "$Id: Makefile.in,v 1.24.2.1 1999/12/03 17:43:49 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.3
VERSION = 0.0
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -33,15 +33,12 @@ VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
mandir = @mandir@
includedir = $(prefix)/include
dllib=@DLLIB@
rdynamic=@rdynamic@
CC = @CC@
CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
STRIP = @STRIP@
@@ -50,46 +47,33 @@ CPPFLAGS = @CPPFLAGS@ @DEFS@
CXXFLAGS = @CXXFLAGS@ -I$(srcdir)
LDFLAGS = @LDFLAGS@
all: ivl@EXEEXT@
cd vvm ; $(MAKE) all
all: ivl verilog
cd vpi ; $(MAKE) all
cd vvm ; $(MAKE) all
cd ivlpp ; $(MAKE) all
cd driver ; $(MAKE) all
cd tgt-verilog ; $(MAKE) all
cd tgt-stub ; $(MAKE) all
clean:
rm -f *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc lexor_keyword.cc verilog iverilog@EXEEXT@
cd vvm ; $(MAKE) clean
rm -f *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc verilog
cd vpi ; $(MAKE) clean
cd driver ; $(MAKE) clean
cd vvm ; $(MAKE) clean
cd ivlpp ; $(MAKE) clean
cd tgt-verilog ; $(MAKE) clean
cd tgt-stub ; $(MAKE) clean
distclean: clean
rm -f vvm/Makefile
rm -f vpi/Makefile
rm -f vvm/Makefile
rm -f ivlpp/Makefile
rm -f driver/Makefile
rm -f config.status config.cache config.log
rm -f Makefile
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o t-null.o \
t-verilog.o t-vvm.o t-xnf.o
FF = nodangle.o synth.o syn-rules.o xnfio.o
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 dup_expr.o elaborate.o elab_expr.o \
elab_lval.o elab_net.o elab_pexpr.o elab_scope.o elab_sig.o emit.o eval.o \
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
mangle.o netlist.o net_assign.o \
net_design.o net_event.o net_force.o net_link.o net_modulo.o net_proc.o \
net_scope.o net_udp.o \
pad_to_width.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 util.o Module.o PDelays.o PEvent.o \
PExpr.o PGate.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)
@@ -107,16 +91,14 @@ verilog: $(srcdir)/verilog.sh
sed -e 's;@$(tmp1)@;@bindir@;' \
-e 's;@$(tmp2)@;@libdir@;' \
-e 's;@$(tmp3)@;@includedir@;' \
-e 's;@dllib@;@DLLIB@;' \
-e 's;@$(tmp4)@;@CXX@;' < $< > $@
ivl@EXEEXT@: $O
$(CXX) $(CXXFLAGS) $(rdynamic) -o ivl@EXEEXT@ $O $(dllib)
ivl: $O
$(CXX) $(CXXFLAGS) -o ivl $O
%.o: %.cc
%.o dep/%.d: %.cc
@[ -d dep ] || mkdir dep
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o
$(CXX) $(CXXFLAGS) -MD -c $< -o $*.o
mv $*.d dep/$*.d
@@ -128,43 +110,31 @@ parse.h parse.cc: $(srcdir)/parse.y
bison --verbose -t -p VL -d $(srcdir)/parse.y -o parse.cc
mv parse.cc.h parse.h
syn-rules.cc: $(srcdir)/syn-rules.y
bison --verbose -p syn_ -o syn-rules.cc $(srcdir)/syn-rules.y
lexor.cc: $(srcdir)/lexor.lex
flex -PVL -s -olexor.cc $(srcdir)/lexor.lex
lexor_keyword.o dep/lexor_keyword.d: lexor_keyword.cc
lexor_keyword.cc: lexor_keyword.gperf
gperf -o -i 7 -C -k 1-3,$$ -L ANSI-C -H keyword_hash -N check_identifier -t lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/iverilog.conf $(includedir)/ivl_target.h
cd vvm ; $(MAKE) install
install: all installdirs $(bindir)/verilog $(libdir)/ivl/ivl $(mandir)/man1/verilog.1
cd vpi ; $(MAKE) install
cd vvm ; $(MAKE) install
cd ivlpp ; $(MAKE) install
cd driver ; $(MAKE) install
$(libdir)/ivl/ivl@EXEEXT@: ./ivl@EXEEXT@
$(INSTALL_PROGRAM) ./ivl@EXEEXT@ $(libdir)/ivl/ivl@EXEEXT@
$(STRIP) $(libdir)/ivl/ivl@EXEEXT@
$(bindir)/verilog: ./verilog
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
$(libdir)/ivl/iverilog.conf: $(srcdir)/iverilog.conf
$(INSTALL_DATA) $(srcdir)/iverilog.conf $(libdir)/ivl/iverilog.conf
$(libdir)/ivl/ivl: ivl
$(INSTALL_PROGRAM) ./ivl $(libdir)/ivl/ivl
$(STRIP) $(libdir)/ivl/ivl
$(includedir)/ivl_target.h: $(srcdir)/ivl_target.h
$(INSTALL_DATA) $(srcdir)/ivl_target.h $(includedir)/ivl_target.h
$(mandir)/man1/verilog.1: $(srcdir)/verilog.1
$(INSTALL_DATA) $(srcdir)/verilog.1 $(mandir)/man1/verilog.1
installdirs: mkinstalldirs
$(srcdir)/mkinstalldirs $(bindir) $(includedir) $(libdir)/ivl
$(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1
uninstall:
rm -f $(libdir)/ivl/ivl@EXEEXT@
rm -f $(bindir)/verilog@EXEEXT@
rm -f $(bindir)/gverilog@EXEEXT@
rm -f $(includedir)/ivl_target.h
cd driver ; $(MAKE) 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
+20 -61
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
* Copyright (c) 1998 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
@@ -16,21 +16,26 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: Module.cc,v 1.12 2000/05/16 04:05:15 steve Exp $"
#if !defined(WINNT)
#ident "$Id: Module.cc,v 1.7 1999/09/17 02:06:25 steve Exp $"
#endif
# include "Module.h"
# include "PGate.h"
# include "PWire.h"
# include <assert.h>
Module::Module(const string&name, const svector<Module::port_t*>*pp)
: name_(name)
{
if (pp)
if (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]);
}
}
}
void Module::add_gate(PGate*gate)
@@ -48,14 +53,9 @@ void Module::add_function(const string &name, PFunction *func)
funcs_[name] = func;
}
PWire* Module::add_wire(PWire*wire)
void Module::add_wire(PWire*wire)
{
PWire*&ep = wires_[wire->name()];
if (ep) return ep;
assert(ep == 0);
ep = wire;
return wire;
wires_.push_back(wire);
}
void Module::add_behavior(PProcess*b)
@@ -68,10 +68,10 @@ unsigned Module::port_count() const
return ports_.count();
}
const svector<PEIdent*>& Module::get_port(unsigned idx) const
const svector<PWire*>& Module::get_port(unsigned idx) const
{
assert(idx < ports_.count());
return ports_[idx]->expr;
return ports_[idx]->wires;
}
unsigned Module::find_port(const string&name) const
@@ -85,63 +85,22 @@ unsigned Module::find_port(const string&name) const
}
PWire* Module::get_wire(const string&name) const
PWire* Module::get_wire(const string&name)
{
map<string,PWire*>::const_iterator obj = wires_.find(name);
if (obj == wires_.end())
return 0;
else
return (*obj).second;
}
PGate* Module::get_gate(const string&name)
{
for (list<PGate*>::iterator cur = gates_.begin()
; cur != gates_.end()
for (list<PWire*>::iterator cur = wires_.begin()
; cur != wires_.end()
; cur ++ ) {
if ((*cur)->get_name() == name)
if ((*cur)->name() == name)
return *cur;
}
return 0;
}
const map<string,PWire*>& Module::get_wires() const
{
return wires_;
}
const list<PGate*>& Module::get_gates() const
{
return gates_;
}
const list<PProcess*>& Module::get_behaviors() const
{
return behaviors_;
}
/*
* $Log: Module.cc,v $
* Revision 1.12 2000/05/16 04:05:15 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.11 2000/03/12 17:09:40 steve
* Support localparam.
*
* Revision 1.10 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.9 2000/01/09 20:37:57 steve
* Careful with wires connected to multiple ports.
*
* Revision 1.8 1999/12/11 05:45:41 steve
* Fix support for attaching attributes to primitive gates.
*
* Revision 1.7 1999/09/17 02:06:25 steve
* Handle unconnected module ports.
*
+14 -75
View File
@@ -1,7 +1,7 @@
#ifndef __Module_H
#define __Module_H
/*
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
* Copyright (c) 1998 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
@@ -18,18 +18,15 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: Module.h,v 1.20 2000/07/22 22:09:03 steve Exp $"
#if !defined(WINNT)
#ident "$Id: Module.h,v 1.10 1999/11/27 19:07:57 steve Exp $"
#endif
# include <list>
# include <map>
# include "svector.h"
# include "named.h"
# include <string>
class PEvent;
class PExpr;
class PEIdent;
class PGate;
class PTask;
class PFunction;
@@ -54,7 +51,9 @@ class Module {
public:
struct port_t {
string name;
svector<PEIdent*> expr;
svector<PWire*>wires;
port_t(int c=0) : wires(c) { }
};
public:
@@ -65,13 +64,6 @@ class Module {
module is elaborated. During parsing, I put the parameters
into this map. */
map<string,PExpr*>parameters;
map<string,PExpr*>localparams;
/* The module also has defparam assignments which don't create
new parameters within the module, but may be used to set
values within this module (when instantiated) or in other
instantiated modules. */
map<string,PExpr*>defparms;
/* Parameters may be overridden at instantiation time;
the overrides do not contain explicit parameter names,
@@ -81,51 +73,34 @@ class Module {
a parameter-index to its name. */
list<string> param_names;
/* Keep a table of named events declared in the module. */
map<string,PEvent*>events;
/* These are the timescale for this module. The default is
set by the `timescale directive. */
int time_unit, time_precision;
const string&get_name() const { return name_; }
void add_gate(PGate*gate);
// The add_wire method adds a wire by name, but only if the
// wire name doesn't already exist. Either way, the result is
// the existing wire or the pointer passed in.
PWire* add_wire(PWire*wire);
void add_wire(PWire*wire);
void add_behavior(PProcess*behave);
void add_task(const string&name, PTask*def);
void add_function(const string&name, PFunction*def);
unsigned port_count() const;
const svector<PEIdent*>& get_port(unsigned idx) const;
const svector<PWire*>& get_port(unsigned idx) const;
unsigned find_port(const string&) const;
// Find a wire by name. This is used for connecting gates to
// existing wires, etc.
PWire* get_wire(const string&name) const;
PGate* get_gate(const string&name);
PWire* get_wire(const string&name);
const map<string,PWire*>& get_wires() const;
const list<PGate*>& get_gates() const;
const list<PProcess*>& get_behaviors() const;
const list<PWire*>& get_wires() const { return wires_; }
const list<PGate*>& get_gates() const { return gates_; }
const list<PProcess*>& get_behaviors() const { return behaviors_; }
void dump(ostream&out) const;
bool elaborate(Design*, NetScope*scope) const;
bool elaborate_scope(Design*, NetScope*scope) const;
bool elaborate_sig(Design*, NetScope*scope) const;
bool elaborate(Design*, NetScope*scope, svector<PExpr*>*overrides_) const;
private:
const string name_;
svector<port_t*> ports_;
map<string,PWire*> wires_;
list<PWire*> wires_;
list<PGate*> gates_;
list<PProcess*> behaviors_;
map<string,PTask*> tasks_;
@@ -139,42 +114,6 @@ class Module {
/*
* $Log: Module.h,v $
* Revision 1.20 2000/07/22 22:09:03 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.19 2000/05/16 04:05:15 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.18 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
* Revision 1.17 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.16 2000/03/12 17:09:40 steve
* Support localparam.
*
* Revision 1.15 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.14 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.13 2000/01/09 20:37:57 steve
* Careful with wires connected to multiple ports.
*
* Revision 1.12 2000/01/09 05:50:48 steve
* Support named parameter override lists.
*
* Revision 1.11 1999/12/11 05:45:41 steve
* Fix support for attaching attributes to primitive gates.
*
* Revision 1.10 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
+2 -5
View File
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PDelays.cc,v 1.2 2000/02/23 02:56:53 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PDelays.cc,v 1.1 1999/09/04 19:11:46 steve Exp $"
#endif
# include "PDelays.h"
@@ -96,9 +96,6 @@ void PDelays::eval_delays(Design*des, const string&path,
/*
* $Log: PDelays.cc,v $
* Revision 1.2 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
+2 -5
View File
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PDelays.h,v 1.2 2000/02/23 02:56:53 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PDelays.h,v 1.1 1999/09/04 19:11:46 steve Exp $"
#endif
# include "svector.h"
@@ -60,9 +60,6 @@ ostream& operator << (ostream&o, const PDelays&);
/*
* $Log: PDelays.h,v $
* Revision 1.2 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
-45
View File
@@ -1,45 +0,0 @@
/*
* Copyright (c) 200Stephen 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) && !defined(macintosh)
#ident "$Id: PEvent.cc,v 1.1 2000/04/01 19:31:57 steve Exp $"
#endif
# include "PEvent.h"
PEvent::PEvent(const string&n)
: name_(n)
{
}
PEvent::~PEvent()
{
}
string PEvent::name() const
{
return name_;
}
/*
* $Log: PEvent.cc,v $
* Revision 1.1 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
*/
-65
View File
@@ -1,65 +0,0 @@
#ifndef __PEvent_H
#define __PEvent_H
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: PEvent.h,v 1.3 2000/04/09 17:44:30 steve Exp $"
#endif
# include "LineInfo.h"
# include <string>
class ostream;
class Design;
class NetScope;
/*
* The PEvent class represents event objects. These are things that
* are declared in Verilog as ``event foo;''
*/
class PEvent : public LineInfo {
public:
explicit PEvent(const string&name);
~PEvent();
string name() const;
void elaborate_scope(Design*des, NetScope*scope) const;
private:
string name_;
private: // not implemented
PEvent(const PEvent&);
PEvent& operator= (const PEvent&);
};
/*
* $Log: PEvent.h,v $
* Revision 1.3 2000/04/09 17:44:30 steve
* Catch event declarations during scope elaborate.
*
* Revision 1.2 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
* Revision 1.1 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
*/
#endif
+10 -150
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-1999 Stephen Williams <[email protected]>
* Copyright (c) 1998 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
@@ -16,18 +16,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PExpr.cc,v 1.19 2000/06/30 15:50:20 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PExpr.cc,v 1.11 1999/10/31 04:11:27 steve Exp $"
#endif
# include "PExpr.h"
# include "Module.h"
# include <typeinfo>
PExpr::PExpr()
{
}
PExpr::~PExpr()
{
}
@@ -45,18 +41,16 @@ bool PExpr::is_constant(Module*) const
NetNet* PExpr::elaborate_net(Design*des, const string&path, unsigned,
unsigned long,
unsigned long,
unsigned long,
Link::strength_t,
Link::strength_t) const
unsigned long) const
{
cerr << get_line() << ": error: Unable to elaborate `"
<< *this << "' as gates." << endl;
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() << ": error: expression not valid in assign l-value: "
cerr << get_line() << ": expression not valid in assign l-value: "
<< *this << endl;
return 0;
}
@@ -66,25 +60,15 @@ bool PEBinary::is_constant(Module*mod) const
return left_->is_constant(mod) && right_->is_constant(mod);
}
PECallFunction::PECallFunction(const char*n, const svector<PExpr *> &parms)
PECallFunction::PECallFunction(const string &n, const svector<PExpr *> &parms)
: name_(n), parms_(parms)
{
}
PECallFunction::PECallFunction(const char*n)
: name_(n)
{
}
PECallFunction::~PECallFunction()
{
}
PEConcat::PEConcat(const svector<PExpr*>&p, PExpr*r)
: parms_(p), repeat_(r)
{
}
bool PEConcat::is_constant(Module *mod) const
{
bool constant = repeat_? repeat_->is_constant(mod) : true;
@@ -99,70 +83,14 @@ PEConcat::~PEConcat()
delete repeat_;
}
PEEvent::PEEvent(PEEvent::edge_t t, PExpr*e)
: type_(t), expr_(e)
{
}
PEEvent::~PEEvent()
{
}
PEEvent::edge_t PEEvent::type() const
{
return type_;
}
PExpr* PEEvent::expr() const
{
return expr_;
}
PEIdent::PEIdent(const string&s)
: text_(s), msb_(0), lsb_(0), idx_(0)
{
}
PEIdent::~PEIdent()
{
}
string PEIdent::name() const
{
return text_;
}
/*
* An identifier can be in a constant expresion if (and only if) it is
* a parameter.
*/
bool PEIdent::is_constant(Module*mod) const
{
map<string,PExpr*>::const_iterator cur;
cur = mod->parameters.find(text_);
if (cur != mod->parameters.end()) return true;
cur = mod->localparams.find(text_);
if (cur != mod->localparams.end()) return true;
return false;
}
PENumber::PENumber(verinum*vp)
: value_(vp)
{
assert(vp);
}
PENumber::~PENumber()
{
delete value_;
}
const verinum& PENumber::value() const
{
return *value_;
map<string,PExpr*>::const_iterator cur = mod->parameters.find(text_);
return cur != mod->parameters.end();
}
bool PENumber::is_the_same(const PExpr*that) const
@@ -179,20 +107,6 @@ bool PENumber::is_constant(Module*) const
return true;
}
PEString::PEString(const string&s)
: text_(s)
{
}
PEString::~PEString()
{
}
string PEString::value() const
{
return text_;
}
bool PEString::is_constant(Module*) const
{
return true;
@@ -212,62 +126,8 @@ bool PETernary::is_constant(Module*) const
return false;
}
PEUnary::PEUnary(char op, PExpr*ex)
: op_(op), expr_(ex)
{
}
PEUnary::~PEUnary()
{
}
bool PEUnary::is_constant(Module*m) const
{
return expr_->is_constant(m);
}
/*
* $Log: PExpr.cc,v $
* Revision 1.19 2000/06/30 15:50:20 steve
* Allow unary operators in constant expressions.
*
* Revision 1.18 2000/05/07 04:37:55 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.17 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.16 2000/04/12 04:23:57 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.15 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.14 2000/03/12 18:22:11 steve
* Binary and unary operators in parameter expressions.
*
* Revision 1.13 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.12 1999/12/31 17:38:37 steve
* Standardize some of the error messages.
*
* Revision 1.11 1999/10/31 04:11:27 steve
* Add to netlist links pin name and instance number,
* and arrange in vvm for pin connections by name
+46 -209
View File
@@ -1,7 +1,7 @@
#ifndef __PExpr_H
#define __PExpr_H
/*
* Copyright (c) 1998-2000 Stephen Williams <[email protected]>
* Copyright (c) 1998-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
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PExpr.h,v 1.44 2000/09/17 21:26:15 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PExpr.h,v 1.25 1999/11/21 00:13:08 steve Exp $"
#endif
# include <string>
@@ -32,7 +32,6 @@ class Design;
class Module;
class NetNet;
class NetExpr;
class NetScope;
/*
* The PExpr class hierarchy supports the description of
@@ -44,21 +43,13 @@ class NetScope;
*/
class PExpr : public LineInfo {
public:
PExpr();
virtual ~PExpr();
virtual void dump(ostream&) const;
// Procedural elaboration of the expression.
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope) const;
// Elaborate expressions that are the r-value of parameter
// assignments. This elaboration follows the restrictions of
// constant expressions and supports later overriding and
// evaluation of parameters.
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
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 wholly structural context.
@@ -66,19 +57,12 @@ class PExpr : public LineInfo {
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay,
Link::strength_t drive0 =Link::STRONG,
Link::strength_t drive1 =Link::STRONG)
const;
unsigned long decay) 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;
// Expressions that can be in the l-value of procedural
// assignments can be elaborated with this method.
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
// This attempts to evaluate a constant expression, and return
// a verinum as a result. If the expression cannot be
// evaluated, return 0.
@@ -95,9 +79,6 @@ class PExpr : public LineInfo {
// of expresions.
virtual bool is_constant(Module*) const;
private: // not implemented
PExpr(const PExpr&);
PExpr& operator= (const PExpr&);
};
ostream& operator << (ostream&, const PExpr&);
@@ -105,7 +86,8 @@ ostream& operator << (ostream&, const PExpr&);
class PEConcat : public PExpr {
public:
PEConcat(const svector<PExpr*>&p, PExpr*r =0);
PEConcat(const svector<PExpr*>&p, PExpr*r =0)
: parms_(p), repeat_(r) { }
~PEConcat();
virtual void dump(ostream&) const;
@@ -114,12 +96,8 @@ class PEConcat : public PExpr {
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*) const;
virtual NetEConcat*elaborate_pexpr(Design*des, NetScope*) const;
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual bool is_constant(Module*) const;
private:
@@ -127,67 +105,48 @@ class PEConcat : public PExpr {
PExpr*repeat_;
};
/*
* Event expressions are expressions that can be combined with the
* event "or" operator. These include "posedge foo" and similar, and
* also include named events. "edge" events are associated with an
* expression, whereas named events simply have a name, which
* represents an event variable.
*/
class PEEvent : public PExpr {
public:
enum edge_t {ANYEDGE, POSEDGE, NEGEDGE, POSITIVE};
PEEvent(NetNEvent::Type t, PExpr*e)
: type_(t), expr_(e)
{ }
// Use this constructor to create events based on edges or levels.
PEEvent(edge_t t, PExpr*e);
NetNEvent::Type type() const { return type_; }
PExpr* expr() const { return expr_; }
~PEEvent();
edge_t type() const;
PExpr* expr() const;
virtual void dump(ostream&) const;
private:
edge_t type_;
PExpr *expr_;
NetNEvent::Type type_;
PExpr*expr_;
};
class PEIdent : public PExpr {
public:
explicit PEIdent(const string&s);
~PEIdent();
explicit PEIdent(const string&s)
: 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;
// Identifiers are also allowed as procedural assignment l-values.
virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope) const;
// Structural r-values are OK.
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
// Elaborate the PEIdent as a port to a module. This method
// only applies to Ident expressions.
NetNet* elaborate_port(Design*des, NetScope*sc) 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;
string name() const;
// XXXX
string name() const { return text_; }
private:
string text_;
@@ -211,21 +170,19 @@ class PEIdent : public PExpr {
class PENumber : public PExpr {
public:
explicit PENumber(verinum*vp);
~PENumber();
explicit PENumber(verinum*vp)
: value_(vp) { assert(vp); }
~PENumber() { delete value_; }
const verinum& value() const;
const verinum& value() const { return *value_; }
virtual void dump(ostream&) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetEConst*elaborate_expr(Design*des, NetScope*) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
virtual bool is_the_same(const PExpr*that) const;
@@ -238,13 +195,12 @@ class PENumber : public PExpr {
class PEString : public PExpr {
public:
explicit PEString(const string&s);
~PEString();
explicit PEString(const string&s)
: text_(s) { }
string value() const;
string value() const { return text_; }
virtual void dump(ostream&) const;
virtual NetEConst*elaborate_expr(Design*des, NetScope*) const;
virtual NetEConst*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual bool is_constant(Module*) const;
@@ -255,22 +211,16 @@ class PEString : public PExpr {
class PEUnary : public PExpr {
public:
explicit PEUnary(char op, PExpr*ex);
~PEUnary();
explicit PEUnary(char op, PExpr*ex)
: op_(op), expr_(ex) { }
virtual void dump(ostream&out) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetEUnary*elaborate_expr(Design*des, NetScope*) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
virtual bool is_constant(Module*) const;
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
private:
char op_;
@@ -290,11 +240,8 @@ class PEBinary : public PExpr {
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetEBinary*elaborate_expr(Design*des, NetScope*) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
unsigned long decay) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
private:
@@ -302,43 +249,16 @@ class PEBinary : public PExpr {
PExpr*left_;
PExpr*right_;
NetEBinary*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp) const;
NetNet* elaborate_net_add_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_bit_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_cmp_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_div_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_mod_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_log_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_mul_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
unsigned long fall,
unsigned long decay) const;
NetNet* elaborate_net_shift_(Design*des, const string&path,
unsigned lwidth,
unsigned long rise,
@@ -361,12 +281,10 @@ class PETernary : public PExpr {
virtual void dump(ostream&out) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned width,
unsigned long rise,
unsigned long fall,
unsigned long decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
virtual NetETernary*elaborate_expr(Design*des, NetScope*) const;
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual verinum* eval_const(const Design*des, const string&path) const;
private:
@@ -376,106 +294,25 @@ class PETernary : public PExpr {
};
/*
* This class represents a parsed call to a function, including calls
* to system functions.
* This class represents a parsed call to a function.
*/
class PECallFunction : public PExpr {
public:
explicit PECallFunction(const char*n, const svector<PExpr *> &parms);
explicit PECallFunction(const char*n);
explicit PECallFunction(const string &n, const svector<PExpr *> &parms);
~PECallFunction();
virtual void dump(ostream &) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
private:
string name_;
svector<PExpr *> parms_;
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope) const;
NetESFunc* elaborate_sfunc_(Design*des, const string&path) const;
};
/*
* $Log: PExpr.h,v $
* Revision 1.44 2000/09/17 21:26:15 steve
* Add support for modulus (Eric Aardoom)
*
* Revision 1.43 2000/09/09 15:21:26 steve
* move lval elaboration to PExpr virtual methods.
*
* Revision 1.42 2000/09/07 22:38:13 steve
* Support unary + and - in constants.
*
* Revision 1.41 2000/06/30 15:50:20 steve
* Allow unary operators in constant expressions.
*
* Revision 1.40 2000/06/13 05:22:16 steve
* Support concatenation in parameter expressions.
*
* Revision 1.39 2000/06/01 02:31:39 steve
* Parameters can be strings.
*
* Revision 1.38 2000/05/16 04:05:15 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.37 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.36 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.35 2000/04/12 04:23:57 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.34 2000/04/01 21:40:22 steve
* Add support for integer division.
*
* Revision 1.33 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.32 2000/03/12 18:22:11 steve
* Binary and unary operators in parameter expressions.
*
* Revision 1.31 2000/03/12 04:35:22 steve
* Allow parameter identifiers in parameter expressions.
*
* Revision 1.30 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.29 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.28 2000/02/16 03:58:27 steve
* Fix up width matching in structural bitwise operators.
*
* Revision 1.27 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.26 1999/12/16 03:46:39 steve
* Structural logical or.
*
* Revision 1.25 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
+2 -5
View File
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PFunction.cc,v 1.3 2000/02/23 02:56:53 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PFunction.cc,v 1.2 1999/08/25 22:22:41 steve Exp $"
#endif
#include "PTask.h"
@@ -39,9 +39,6 @@ void PFunction::set_output(PWire*o)
/*
* $Log: PFunction.cc,v $
* Revision 1.3 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
+3 -85
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2000 Stephen Williams ([email protected])
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PGate.cc,v 1.9 2000/05/06 15:41:56 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PGate.cc,v 1.5 1999/09/14 01:50:35 steve Exp $"
#endif
# include "PGate.h"
@@ -31,8 +31,6 @@ PGate::PGate(const string&name,
: name_(name), pins_(pins)
{
if (del) delay_.set_delays(del);
str0_ = STRONG;
str1_ = STRONG;
}
PGate::PGate(const string&name,
@@ -41,45 +39,17 @@ PGate::PGate(const string&name,
: name_(name), pins_(pins)
{
if (del) delay_.set_delay(del);
str0_ = STRONG;
str1_ = STRONG;
}
PGate::PGate(const string&name, svector<PExpr*>*pins)
: name_(name), pins_(pins)
{
str0_ = STRONG;
str1_ = STRONG;
}
PGate::~PGate()
{
}
PGate::strength_t PGate::strength0() const
{
return str0_;
}
void PGate::strength0(PGate::strength_t s)
{
str0_ = s;
}
PGate::strength_t PGate::strength1() const
{
return str1_;
}
void PGate::strength1(PGate::strength_t s)
{
str1_ = s;
}
void PGate::elaborate_scope(Design*, NetScope*) const
{
}
/*
* This method is used during elaboration to calculate the
* rise/fall/decay times for the gate. These values were set in pform
@@ -140,60 +110,8 @@ void PGBuiltin::set_range(PExpr*msb, PExpr*lsb)
lsb_ = lsb;
}
PGModule::PGModule(const string&type, const string&name, svector<PExpr*>*pins)
: PGate(name, pins), type_(type), overrides_(0), pins_(0),
npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0)
{
}
PGModule::PGModule(const string&type, const string&name,
named<PExpr*>*pins, unsigned npins)
: PGate(name, 0), type_(type), overrides_(0), pins_(pins),
npins_(npins), parms_(0), nparms_(0), msb_(0), lsb_(0)
{
}
void PGModule::set_parameters(svector<PExpr*>*o)
{
assert(overrides_ == 0);
overrides_ = o;
}
void PGModule::set_parameters(named<PExpr*>*pa, unsigned npa)
{
assert(parms_ == 0);
assert(overrides_ == 0);
parms_ = pa;
nparms_ = npa;
}
void PGModule::set_range(PExpr*msb, PExpr*lsb)
{
assert(msb_ == 0);
assert(lsb_ == 0);
msb_ = msb;
lsb_ = lsb;
}
/*
* $Log: PGate.cc,v $
* Revision 1.9 2000/05/06 15:41:56 steve
* Carry assignment strength to pform.
*
* Revision 1.8 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.7 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.6 2000/02/18 05:15:02 steve
* Catch module instantiation arrays.
*
* Revision 1.5 1999/09/14 01:50:35 steve
* Handle gates without delays.
*
+13 -80
View File
@@ -1,7 +1,7 @@
#ifndef __PGate_H
#define __PGate_H
/*
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
* Copyright (c) 1998-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
@@ -18,20 +18,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PGate.h,v 1.18 2000/05/06 15:41:56 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PGate.h,v 1.10 1999/09/04 19:11:46 steve Exp $"
#endif
# include "svector.h"
# include "named.h"
# include "LineInfo.h"
# include "PDelays.h"
# include <map>
# include <string>
class PExpr;
class PUdp;
class Design;
class NetScope;
class Module;
/*
@@ -42,17 +38,10 @@ class Module;
* This pins of a gate are connected to expressions. The elaboration
* step will need to convert expressions to a network of gates in
* order to elaborate expression inputs, but that can easily be done.
*
* The PGate base class also carries the strength0 and strength1
* strengths for those gates where the driver[s] can be described by a
* single strength pair. There is a strength of the 0 drive, and a
* strength of the 1 drive.
*/
class PGate : public LineInfo {
public:
enum strength_t { HIGHZ, WEAK, PULL, STRONG, SUPPLY };
explicit PGate(const string&name, svector<PExpr*>*pins,
const svector<PExpr*>*del);
@@ -73,18 +62,8 @@ class PGate : public LineInfo {
unsigned pin_count() const { return pins_? pins_->count() : 0; }
const PExpr*pin(unsigned idx) const { return (*pins_)[idx]; }
strength_t strength0() const;
strength_t strength1() const;
void strength0(strength_t);
void strength1(strength_t);
map<string,string> attributes;
virtual void dump(ostream&out) const;
virtual void elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*sc) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
protected:
const svector<PExpr*>* get_pins() const { return pins_; }
@@ -97,8 +76,6 @@ class PGate : public LineInfo {
PDelays delay_;
svector<PExpr*>*pins_;
strength_t str0_, str1_;
private: // not implemented
PGate(const PGate&);
PGate& operator= (const PGate&);
@@ -174,79 +151,35 @@ 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);
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.
struct bind_t {
string name;
PExpr* parm;
};
explicit PGModule(const string&type, const string&name,
named<PExpr*>*pins, unsigned npins);
svector<PExpr*>*overrides, bind_t*pins, unsigned npins)
: PGate(name, 0), type_(type), overrides_(overrides), pins_(pins), npins_(npins) { }
// Parameter overrides can come as an ordered list, or a set
// of named expressions.
void set_parameters(svector<PExpr*>*o);
void set_parameters(named<PExpr*>*pa, unsigned npa);
// Modules can be instantiated in ranges. The parser uses this
// method to pass the range to the pform.
void set_range(PExpr*msb, PExpr*lsb);
virtual void dump(ostream&out) const;
virtual void elaborate(Design*, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*sc) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
private:
string type_;
svector<PExpr*>*overrides_;
named<PExpr*>*pins_;
bind_t*pins_;
unsigned npins_;
// These members support parameter override by name
named<PExpr*>*parms_;
unsigned nparms_;
// Arrays of modules are give if these are set.
PExpr*msb_;
PExpr*lsb_;
void elaborate_mod_(Design*, Module*mod, const string&path) const;
void elaborate_sudp_(Design*, PUdp *udp, const string&path) const;
void elaborate_cudp_(Design*, PUdp *udp, const string&path) const;
void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const;
bool elaborate_sig_mod_(Design*des, NetScope*scope, Module*mod) const;
void elaborate_udp_(Design*, PUdp *udp, const string&path) const;
};
/*
* $Log: PGate.h,v $
* Revision 1.18 2000/05/06 15:41:56 steve
* Carry assignment strength to pform.
*
* Revision 1.17 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
* Revision 1.16 2000/03/29 04:37:10 steve
* New and improved combinational primitives.
*
* Revision 1.15 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.14 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.13 2000/02/18 05:15:02 steve
* Catch module instantiation arrays.
*
* Revision 1.12 2000/01/09 05:50:48 steve
* Support named parameter override lists.
*
* Revision 1.11 1999/12/11 05:45:41 steve
* Fix support for attaching attributes to primitive gates.
*
* Revision 1.10 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
+2 -5
View File
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PTask.cc,v 1.3 2000/02/23 02:56:53 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PTask.cc,v 1.2 1999/07/24 02:11:19 steve Exp $"
#endif
# include "PTask.h"
@@ -33,9 +33,6 @@ PTask::~PTask()
/*
* $Log: PTask.cc,v $
* Revision 1.3 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/07/24 02:11:19 steve
* Elaborate task input ports.
*
+8 -39
View File
@@ -1,7 +1,7 @@
#ifndef __PTask_H
#define __PTask_H
/*
* Copyright (c) 1999-2000 Stephen Williams ([email protected])
* 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
@@ -18,15 +18,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PTask.h,v 1.9 2000/07/30 18:25:43 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PTask.h,v 1.6 1999/09/30 21:28:34 steve Exp $"
#endif
# include "LineInfo.h"
# include "svector.h"
# include <string>
class Design;
class NetScope;
class PWire;
class Statement;
@@ -39,17 +38,8 @@ class PTask : public LineInfo {
explicit PTask(svector<PWire*>*p, Statement*s);
~PTask();
// Tasks introduce scope, to need to be handled during the
// scope elaboration pass. The scope passed is my scope,
// created by the containing scope. I fill it in with stuff if
// I need to.
void elaborate_scope(Design*des, NetScope*scope) const;
// Bind the ports to the regs that are the ports.
void elaborate_sig(Design*des, NetScope*scope) const;
// Elaborate the statement to finish off the task definition.
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;
@@ -75,13 +65,9 @@ class PFunction : public LineInfo {
void set_output(PWire*);
void elaborate_scope(Design*des, NetScope*scope) const;
/* elaborate the ports and return value. */
void elaborate_sig(Design *des, NetScope*) const;
/* Elaborate the behavioral statement. */
void elaborate(Design *des, NetScope*) const;
/* 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;
@@ -93,23 +79,6 @@ class PFunction : public LineInfo {
/*
* $Log: PTask.h,v $
* Revision 1.9 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.8 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.7 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.6 1999/09/30 21:28:34 steve
* Handle mutual reference of tasks by elaborating
* task definitions in two passes, like functions.
+3 -6
View File
@@ -1,7 +1,7 @@
#ifndef __PUdp_H
#define __PUdp_H
/*
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
* Copyright (c) 1998 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
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PUdp.h,v 1.4 2000/02/23 02:56:53 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PUdp.h,v 1.3 1999/06/15 03:44:53 steve Exp $"
#endif
# include <map>
@@ -82,9 +82,6 @@ class PUdp {
/*
* $Log: PUdp.h,v $
* Revision 1.4 2000/02/23 02:56:53 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/06/15 03:44:53 steve
* Get rid of the STL vector template.
*
+2 -5
View File
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PWire.cc,v 1.3 2000/02/23 02:56:54 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PWire.cc,v 1.2 1999/09/10 05:02:09 steve Exp $"
#endif
# include "PWire.h"
@@ -100,9 +100,6 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
/*
* $Log: PWire.cc,v $
* Revision 1.3 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
+4 -10
View File
@@ -1,7 +1,7 @@
#ifndef __PWire_H
#define __PWire_H
/*
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
* Copyright (c) 1998 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
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: PWire.h,v 1.8 2000/05/02 16:27:38 steve Exp $"
#if !defined(WINNT)
#ident "$Id: PWire.h,v 1.6 1999/11/27 19:07:57 steve Exp $"
#endif
# include "netlist.h"
@@ -58,7 +58,7 @@ class PWire : public LineInfo {
// Write myself to the specified stream.
void dump(ostream&out) const;
void elaborate_sig(Design*, NetScope*scope) const;
void elaborate(Design*, NetScope*scope) const;
private:
string name_;
@@ -82,12 +82,6 @@ class PWire : public LineInfo {
/*
* $Log: PWire.h,v $
* Revision 1.8 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
* Revision 1.7 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.6 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
+122 -179
View File
@@ -1,24 +1,23 @@
THE ICARUS VERILOG COMPILATION SYSTEM
September 17, 2000
September 18, 1999
1.0 What is ICARUS Verilog?
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. For a view of the current state of Icarus Verilog, see its
home page at <http://www.icarus.com/eda/verilog>.
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. For a
view of the current state of Icarus Verilog, see its home page at
<http://www.icarus.com/eda/verilog>.
Icarus Verilog is not aimed at being a simulator in the traditional
sense, but a compiler that generates code employed by back-end
tools. These back- end tools currently include a simulator written in
C++ called VVM and an XNF (Xilinx Netlist Format) generator. See
"vvm.txt" and "xnf.txt" for further details on these back-end
processors. In the future, backends are expected for EDIF/LPM,
structural Verilog, VHDL, etc.
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-
end tools currently include a simulator written in C++ called VVM
and an XNF (Xilinx Netlist Format) generator. See "vvm.txt" and
"xnf.txt" for further details on these back-end processors. In the
future, backends are expected for EDIF/LPM, structural Verilog, etc.
2.0 Building/Installing Icarus Verilog From Source
2.0 Building/Installing IVL From Source
If you are starting from source, the build process is designed to be
as simple as practical. Someone basically familiar with the target
@@ -34,26 +33,15 @@ on a UNIX-like system:
- GNU Make
The Makefiles use some GNU extensions to, so a basic POSIX
make will not work. Linux systems typically come with a
satisfactory make. BSD based systems (i.e. NetBSD, FreeBSD)
typically have GNU make as the gmake program.
satisfactory make.
- ISO C++ Compiler
The ivl and ivlpp programs are written in C++ and makes use
of templates and some of the standard C++ library. egcs and
recent gcc compilers with the associated libstdc++ are known
to work.
The ivl program is written in C++ and makes use of templates
and some of the standard C++ library. egcs compilers with
the associated libstdc++ are known to work.
- bison
- gperf 2.7
The lexical analyzer doesn't recognize keywords directly,
but instead matches symbols and looks them up in a hash
table in order to get the proper lexical code. The gperf
program generates the lookup table.
A version problem with this program is the most common cause
of difficulty. See the Icarus Verilog FAQ.
2.2 Compilation
Unpack the tar-ball and cd into the verilog-######### directory
@@ -72,7 +60,7 @@ root.
make install
3.0 How Icarus Verilog Works
3.0 How IVL Works
This tool includes a parser which reads in Verilog (plus extensions)
and generates an internal netlist. The netlist is passed to various
@@ -98,8 +86,8 @@ 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
``-P <path>'' flag to the compiler. This will cause iverilog to dump
the PFORM into the file named <path>.
``-P <path>'' flag to the compiler. This will cause ivl to dump the
PFORM into the file named <path>.
3.3 Elaboration
@@ -107,8 +95,7 @@ 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.) Final semantic checks are performed during
elaboration, and some simple optimizations are performed. The netlist
includes all the behavioral descriptions, as well as gates and wires.
elaboration, and some simple optimizations are performed.
The elaborate() function performs the elaboration.
@@ -117,31 +104,6 @@ optimized netlist by using the ``-N <path>'' flag to the compiler. If
elaboration succeeds, the final netlist (i.e. after optimizations but
before code generation) will be dumped into the file named <path>.
Elaboration is actually performed it two steps: scopes and parameters
first, followed by the structural and behavioral elaboration.
3.3.1 Scope Elaboration
This pass scans through the pform looking for scopes and parameters. A
tree of NetScope objects is built up and placed in the Design object,
with the root module represented by the root NetScope object. The
elab_scope.cc and elab_pexpr.cc files contain most of the code for
handling this phase.
The tail of the elaborate_scope behavior (after the pform is
traversed) includes a scan of the NetScope tree to locate defparam
assignments that were collected during scope elaboration. This is when
the defparam overrides are applied to the parameters.
3.3.2 Netlist Elaboration
After the scopes and parameters are generated and the NetScope tree
fully formed, the elaboration runs through the pform again, this time
generating the structural and behavioral netlist. Parameters are
elaborated and evaluated by now so all the constants of code
generation are now known locally, so the netlist can be generated by
simply passing through the pform.
3.4 Optimization
This is actually a collection of processing steps that perform
@@ -152,7 +114,7 @@ some useful transformations would be,
- combinational reduction
- Constant propagation
The actual functions performed are specified on the ivl command line by
The actual functions performed are specified on the command line by
the -F flags (See below).
3.5 Code Generation
@@ -165,50 +127,20 @@ The emit() method of the Design class performs this step. It runs
through the design elements, calling target functions as need arises
to generate actual output.
The user selects the target code generator with the -t flag on the
The target code generator to used is given by the -t flag on the
command line.
3.6 ATTRIBUTES
4.0 Running Verilog
The parser accepts as an extension to Verilog the $attribute module
item. The syntax of the $attribute item is:
$attribute (<identifier>, <key>, <value>);
The $attribute keyword looks like a system task invocation. The
difference here is that the parameters are more restricted then those
of a system task. The <identifier> must be an identifier. This will be
the item to get an attribute. The <key> and <value> are strings, not
expressions, that give the key and the value of the attribute to be
attached to the identified object.
Attributes are [<key> <value>] pairs and are used to communicate with
the various processing steps. See the documentation for the processing
step for a list of the pertinent attributes.
Attributes can also be applied to gate types. When this is done, the
attribute is given to every instantiation of the primitive. The syntax
for the attribute statement is the same, except that the <identifier>
names a primitive earlier in the compilation unit and the statement is
placed in global scope, instead of within a module. The semicolon is
not part of a type attribute.
Note that attributes are also occasionally used for communication
between processing steps. Processing steps that are aware of others
may place attributes on netlist objects to communicate information to
later steps.
4.0 Running iverilog
The preferred way to invoke the compiler with the iverilog(1)
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 iverilog(1) man page for usage details.
done in a friendly way. See the verilog(1) man page for usage details.
4.1 Running IVL Directly (not recommended)
4.1 Running IVL Directly
The ivl command is the compiler driver, that invokes the parser,
optimization functions and the code generator, but not the preprocessor.
optimization functions and the code generator.
Usage: ivl <options>... file
ivl -h
@@ -234,17 +166,6 @@ Usage: ivl <options>... file
target specific information to the target back-end, or
options/parameters to optimization functions, if any are defined.
-m <module>
Cause a named VPI module to be included in the module
list. This parameter appends the named module to the end of
the VPI_MODULE_LIST. This is an ordered list of modules to be
loaded into the simulation at runtime.
This list can also be set with -fVPI_MODULE_LIST=<list> which
sets the list completely. Then, -m after this will append
module names to the list sp specified. The default list
includes "system".
-N <file>
Dump the elaborated netlist to the named file. The netlist is
the folly elaborated netlist, after all the function modules
@@ -268,11 +189,6 @@ Usage: ivl <options>... file
file. If there are multiple modules, use this option to select
the module to be used as the top-level module.
-T [min|typ|max]
Normally, ivl will select typ values from min:type:max
expressions and print a warning. This flag tells the compiler
exactly which value to choose, and suppresses the warning.
-t <name>
Select the output format for the compiled result. Use the
"ivl -h" command to get a list of configured targets.
@@ -280,7 +196,39 @@ Usage: ivl <options>... file
-v
Print version and copyright information for ivl.
4.2 EXAMPLES
ATTRIBUTES
The parser accepts as an extension to Verilog the $attribute module
item. The syntax of the $attribute item is:
$attribute (<identifier>, <key>, <value>);
The $attribute keyword looks like a system task invocation. The
difference here is that the parameters are more restricted then those
of a system task. The <identifier> must be an identifier. This will be
the item to get an attribute. The <key> and <value> are strings, not
expressions, that give the key and the value of the attribute to be
attached to the identified object.
Attributes are [<key> <value>] pairs and are used to communicate with
the various processing steps. See the documentation for the processing
step for a list of the pertinent attributes.
Attributes can also be applied to gate types. When this is done, the
attribute is given to every instantiation of the primitive. The syntax
for the attribute statement is the same, except that the <identifier>
names a primitive earlier in the compilation unit and the statement is
placed in global scope, instead of within a module. The semicolon is
not part of a type attribute.
Currently, type attributes are only supported for UDP types.
Note that attributes are also occasionally used for communication
between processing steps. Processing steps that are aware of others
may place attributes on netlist objects to communicate information to
later steps.
4.1 EXAMPLES
Example: Compiling "hello.vl"
@@ -297,30 +245,45 @@ endmodule
--------------------------------------------------------------
Insure that "iverilog" is on your search path, and the vpi library
Insure that "verilog" is on your search path, and the vpi library
is available.
To compile the program:
For csh -
iverilog hello.vl
setenv PATH /usr/local/bin:$PATH
setenv VPI_MODULE_PATH /usr/local/lib/ivl
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 gcc.)
To run the program:
To run the program
./a.out
./hello
You can use the "-o" switch to name the output command to be generated
by the compiler. See the iverilog(1) man page.
5.0 Unsupported Constructs
Icarus Verilog 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. 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.
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. 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);
- Memories work, but only in procedural code.
reg [1:0] b [2:0], bar;
wire [1:0] foo;
always foo = b[i]; // sorry
always @(i) bar = b[i]; // OK
- `timescale directive
- force/release/assign/deassign procedural assignments not
supported.
- block disable not supported, i.e.:
@@ -330,39 +293,62 @@ Verilog web page for the current state of support for Verilog.
[...]
end
- fork/join is not supported in vvm runtime
- Structural shift operators are in general not supported.
Procedural expressions are OK. Constant expressions are OK.
assign foo = a << b; // sorry
always @(a or b) foo = a << b; // OK
parameter 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 supported, but the compiler presumes that
they return 32 bits. This is the typical case.
- system functions are not supported. (User defined functions are
supported, and system tasks are supported.)
- Specify blocks are parsed but ignored in general.
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
- drive strengths are parsed, bug ignored.
Specify blocks are parsed but ignored in general.
6.0 CREDITS
Except where otherwise noted, Icarus Verilog, ivl and ivlpp are
Copyright Stephen 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):
Except where otherwise noted, ivl and ivlpp are Copyright Stephen
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]>
Stephan I. Boettcher <[email protected]>
Ed Carter <[email protected]>
Larry Doolittle <[email protected]>
Guy Hutchison <[email protected]>
Ales Hvezda <[email protected]>
Yasuhisa Kato <[email protected]>
James Lee <[email protected]>
Peter Monta <[email protected]>
Daniel H. Nelsen <[email protected]>
Stefan Petersen <[email protected]>
Jason Schonberg <schonm@yahoo.com>
Jason Schonberg <schon@mips.com>
Stuart Sutherland <[email protected]>
Stephen Tell <[email protected]>
Stefan Theide <[email protected]>
@@ -371,46 +357,3 @@ alphabetical order):
and others. Testers in particular include a larger community of people
interested in a GPL Verilog for Linux. Special thanks to Steve Wilson
for collecting and organizing the test suite code for all those testers.
6.1 PORT MAINTAINERS
This is a list of people who have created ports and precompiled
packages for various operating systems. These folks have graciously
taken on the task of building Icarus Verilog on their systems and
bundled it into neat packages.(*) If you want to be added to the list (or
removed from the list) send e-mail to me.
FreeBSD/{Intel,alpha}
*maintainer needed*
Linux/{alpha,Intel,SPARC} (RPMS)
Stephen Williams <[email protected]>
Linux/* (.debs)
Hamish Moffatt <[email protected]>
Macintosh -- MacO/S
Yasuhisa Kato <[email protected]>
NetBSD/*
Dan <[email protected]>
Solaris/SPARC packages (.pkg)
Dan McMahill <[email protected]>
Cygwin32/*
Venkat Iyer <[email protected]>
(*) These are not the only systems where Icarus Verilog has been run,
just the systems where precompiled binaries are publicly available.
6.2 TEST SUITE MANAGER
Steve Wilson <[email protected]> or <[email protected]> has taken on
the large task of managing the test suite. He has maintained the
regression test scripts, the driver list, received submissions from
myself and others, and has written a great many tests on his own. Any
compiler writer, for any language, will tell you that the test suite
is at least as important as the compiler code itself.
+3 -128
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-1999 Stephen Williams ([email protected])
* Copyright (c) 1998 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: Statement.cc,v 1.22 2000/07/26 05:08:07 steve Exp $"
#if !defined(WINNT)
#ident "$Id: Statement.cc,v 1.16 1999/09/29 18:36:02 steve Exp $"
#endif
# include "Statement.h"
@@ -122,22 +122,6 @@ PCase::~PCase()
delete[]items_;
}
PCAssign::PCAssign(PExpr*l, PExpr*r)
: lval_(l), expr_(r)
{
}
PCAssign::~PCAssign()
{
delete lval_;
delete expr_;
}
PCondit::PCondit(PExpr*ex, Statement*i, Statement*e)
: expr_(ex), if_(i), else_(e)
{
}
PCondit::~PCondit()
{
delete expr_;
@@ -145,68 +129,6 @@ PCondit::~PCondit()
delete else_;
}
PDeassign::PDeassign(PExpr*l)
: lval_(l)
{
}
PDeassign::~PDeassign()
{
delete lval_;
}
PDelayStatement::PDelayStatement(PExpr*d, Statement*st)
: delay_(d), statement_(st)
{
}
PDelayStatement::~PDelayStatement()
{
}
PDisable::PDisable(const string&sc)
: scope_(sc)
{
}
PDisable::~PDisable()
{
}
PEventStatement::PEventStatement(const svector<PEEvent*>&ee)
: expr_(ee), statement_(0)
{
}
PEventStatement::PEventStatement(PEEvent*ee)
: expr_(1), statement_(0)
{
expr_[0] = ee;
}
PEventStatement::~PEventStatement()
{
// delete the events and the statement?
}
void PEventStatement::set_statement(Statement*st)
{
statement_ = st;
}
PForce::PForce(PExpr*l, PExpr*r)
: lval_(l), expr_(r)
{
}
PForce::~PForce()
{
delete lval_;
delete expr_;
}
PForever::PForever(Statement*s)
: statement_(s)
{
@@ -222,16 +144,6 @@ PProcess::~PProcess()
delete statement_;
}
PRelease::PRelease(PExpr*l)
: lval_(l)
{
}
PRelease::~PRelease()
{
delete lval_;
}
PRepeat::PRepeat(PExpr*e, Statement*s)
: expr_(e), statement_(s)
{
@@ -243,15 +155,6 @@ PRepeat::~PRepeat()
delete statement_;
}
PTrigger::PTrigger(const string&e)
: event_(e)
{
}
PTrigger::~PTrigger()
{
}
PWhile::~PWhile()
{
delete cond_;
@@ -260,34 +163,6 @@ PWhile::~PWhile()
/*
* $Log: Statement.cc,v $
* Revision 1.22 2000/07/26 05:08:07 steve
* Parse disable statements to pform.
*
* Revision 1.21 2000/05/11 23:37:26 steve
* Add support for procedural continuous assignment.
*
* Revision 1.20 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.19 2000/04/12 04:23:57 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.18 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.17 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.16 1999/09/29 18:36:02 steve
* Full case support
*
+15 -158
View File
@@ -1,7 +1,7 @@
#ifndef __Statement_H
#define __Statement_H
/*
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
* Copyright (c) 1998 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
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: Statement.h,v 1.29 2000/09/09 15:21:26 steve Exp $"
#if !defined(WINNT)
#ident "$Id: Statement.h,v 1.20 1999/09/29 18:36:02 steve Exp $"
#endif
# include <string>
@@ -30,11 +30,6 @@
class PExpr;
class Statement;
class PEventStatement;
class Design;
class NetAssign_;
class NetCAssign;
class NetDeassign;
class NetScope;
/*
* The PProcess is the root of a behavioral process. Each process gets
@@ -75,7 +70,6 @@ class Statement : public LineInfo {
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
};
/*
@@ -94,7 +88,9 @@ class PAssign_ : public Statement {
const PExpr* rval() const { return rval_; }
protected:
NetAssign_* elaborate_lval(Design*, NetScope*scope) const;
NetNet*elaborate_lval(Design*, const string&path,
unsigned&lsb, unsigned&msb,
NetExpr*&mux) const;
PDelays delay_;
PEventStatement*event_;
@@ -159,7 +155,6 @@ class PBlock : public Statement {
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
private:
string name_;
@@ -209,7 +204,6 @@ class PCase : public Statement {
~PCase();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -223,28 +217,14 @@ class PCase : public Statement {
PCase& operator= (const PCase&);
};
class PCAssign : public Statement {
public:
explicit PCAssign(PExpr*l, PExpr*r);
~PCAssign();
virtual NetCAssign* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
PExpr*lval_;
PExpr*expr_;
};
class PCondit : public Statement {
public:
PCondit(PExpr*ex, Statement*i, Statement*e);
PCondit(PExpr*ex, Statement*i, Statement*e)
: expr_(ex), if_(i), else_(e) { }
~PCondit();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -257,72 +237,34 @@ class PCondit : public Statement {
PCondit& operator= (const PCondit&);
};
class PDeassign : public Statement {
public:
explicit PDeassign(PExpr*l);
~PDeassign();
virtual NetDeassign* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
PExpr*lval_;
};
class PDelayStatement : public Statement {
public:
PDelayStatement(PExpr*d, Statement*st);
~PDelayStatement();
PDelayStatement(PExpr*d, Statement*st)
: delay_(d), statement_(st) { }
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
private:
PExpr*delay_;
Statement*statement_;
};
/*
* This represends the parsing of a disable <scope> statement.
*/
class PDisable : public Statement {
public:
explicit PDisable(const string&sc);
~PDisable();
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
private:
string scope_;
};
/*
* The event statement represents the event delay in behavioral
* code. It comes from such things as:
*
* @name <statement>;
* @(expr) <statement>;
*/
class PEventStatement : public Statement {
public:
explicit PEventStatement(const svector<PEEvent*>&ee);
explicit PEventStatement(PEEvent*ee);
PEventStatement(const svector<PEEvent*>&ee)
: expr_(ee), statement_(0) { }
~PEventStatement();
PEventStatement(PEEvent*ee)
: expr_(1), statement_(0) { expr_[0] = ee; }
void set_statement(Statement*st);
void set_statement(Statement*st) { statement_ = st; }
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
// This method is used to elaborate, but attach a previously
// elaborated statement to the event.
@@ -333,27 +275,12 @@ class PEventStatement : public Statement {
Statement*statement_;
};
class PForce : public Statement {
public:
explicit PForce(PExpr*l, PExpr*r);
~PForce();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
PExpr*lval_;
PExpr*expr_;
};
class PForever : public Statement {
public:
explicit PForever(Statement*s);
~PForever();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -370,7 +297,6 @@ class PForStatement : public Statement {
{ }
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -397,7 +323,6 @@ class PRepeat : public Statement {
~PRepeat();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -405,36 +330,6 @@ class PRepeat : public Statement {
Statement*statement_;
};
class PRelease : public Statement {
public:
explicit PRelease(PExpr*l);
~PRelease();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
PExpr*lval_;
};
/*
* The PTrigger statement sends a trigger to a named event. Take the
* name here.
*/
class PTrigger : public Statement {
public:
explicit PTrigger(const string&ev);
~PTrigger();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
string event_;
};
class PWhile : public Statement {
public:
@@ -443,7 +338,6 @@ class PWhile : public Statement {
~PWhile();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
@@ -453,43 +347,6 @@ class PWhile : public Statement {
/*
* $Log: Statement.h,v $
* Revision 1.29 2000/09/09 15:21:26 steve
* move lval elaboration to PExpr virtual methods.
*
* Revision 1.28 2000/09/03 17:58:35 steve
* Change elaborate_lval to return NetAssign_ objects.
*
* Revision 1.27 2000/07/26 05:08:07 steve
* Parse disable statements to pform.
*
* Revision 1.26 2000/05/11 23:37:26 steve
* Add support for procedural continuous assignment.
*
* Revision 1.25 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.24 2000/04/12 04:23:57 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.23 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.22 2000/03/11 03:25:51 steve
* Locate scopes in statements.
*
* Revision 1.21 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.20 1999/09/29 18:36:02 steve
* Full case support
*
+3 -41
View File
@@ -1,7 +1,7 @@
#ifndef __compiler_H
#define __compiler_H
/*
* Copyright (c) 1999-2000 Stephen Williams ([email protected])
* 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
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: compiler.h,v 1.4 2000/08/20 04:13:56 steve Exp $"
#if !defined(WINNT)
#ident "$Id: compiler.h,v 1.1 1999/06/06 20:42:48 steve Exp $"
#endif
/*
@@ -33,46 +33,8 @@
# define INTEGER_WIDTH 32
#endif
/*
* When doing dynamic linking, we need a uniform way to identify the
* symbol. Some compilers put leading _, some trailing _. The
* configure script figures out which is the local convention and
* defines NEED_LU and NEED_TU as required.
*/
#ifdef NEED_LU
#define LU "_"
#else
#define LU ""
#endif
#ifdef NEED_TU
#define TU "_"
#else
#define TU ""
#endif
/*
* These are flags to enable various sorts of warnings. By default all
* the warnings are of, the -W<list> parameter arranges for each to be
* enabled.
*/
/* Implicit definitions of wires. */
extern bool warn_implicit;
/*
* $Log: compiler.h,v $
* Revision 1.4 2000/08/20 04:13:56 steve
* Add ivl_target support for logic gates, and
* make the interface more accessible.
*
* Revision 1.3 2000/03/17 21:50:25 steve
* Switch to control warnings.
*
* Revision 1.2 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/06/06 20:42:48 steve
* Make compiler width a compile time constant.
*
+1 -86
View File
@@ -7,90 +7,5 @@ AC_PROG_CXX
AC_CHECK_TOOL(STRIP, strip, true)
AC_CHECK_HEADERS(getopt.h)
AC_PROG_INSTALL
AC_CHECK_LIB(dl,main,[DLLIB=-ldl])
AC_SUBST(DLLIB)
AC_CANONICAL_HOST
# $host
#######################
## test for underscores. The vpi module loader in vvm needs to know this
## in order to know the name of the start symbol for the .vpi module.
#######################
AC_CYGWIN
AC_EXEEXT
AC_SUBST(EXEEXT)
AC_MSG_CHECKING("for leading and/or trailing underscores")
cat << EOF > underscore.c
void underscore(void){}
EOF
$CC -shared -c underscore.c > /dev/null 2>&1
CC_LEADING_UNDERSCORE=no
CC_TRAILING_UNDERSCORE=no
output=`nm underscore.o|grep _underscore 2>&1`
if test ! -z "$output" -a -z "$CYGWIN" ; then
CC_LEADING_UNDERSCORE=yes
AC_DEFINE(NEED_LU)
fi
PICFLAG=-fPIC
if test ! -z "$CYGWIN" ; then
PICFLAG=
AC_DEFINE(USE_LIBVPIP)
fi
AC_SUBST(CYGWIN)
AC_SUBST(PICFLAG)
output=`nm underscore.o|grep underscore_ 2>&1`
if test ! -z "$output"; then
CC_TRAILING_UNDERSCORE=yes
AC_DEFINE(NEED_TU)
fi
if test "$CC_LEADING_UNDERSCORE" = yes; then
AC_DEFINE(WLU)
fi
if test "$CC_TRAILING_UNDERSCORE" = yes; then
AC_DEFINE(WTU)
fi
rm underscore.c underscore.o
AC_MSG_RESULT("$CC_LEADING_UNDERSCORE $CC_TRAILING_UNDERSCORE")
#######################
## end of test for underscores
#######################
# The -rdynamic flag is used by iverilog when compiling the target,
# to know how to export symbols of the main program to loadable modules
# that are brought in by -ldl
AC_MSG_CHECKING("for -rdynamic compiler flag")
rdynamic=-rdynamic
case "${host}" in
*-*-netbsd*)
rdynamic="-Wl,--export-dynamic"
;;
*-*-solaris*)
rdynamic=""
;;
*-*-cygwin*)
rdynamic=""
;;
esac
AC_SUBST(rdynamic)
AC_MSG_RESULT($rdynamic)
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile driver/Makefile tgt-stub/Makefile tgt-verilog/Makefile)
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
+123 -420
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
* Copyright (c) 1998 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
@@ -16,17 +16,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: cprop.cc,v 1.17 2000/10/07 19:45:42 steve Exp $"
#if !defined(WINNT)
#ident "$Id: cprop.cc,v 1.2 1998/12/02 04:37:13 steve Exp $"
#endif
# include "netlist.h"
# include "netmisc.h"
# include "functor.h"
# include <assert.h>
/*
* The cprop function below invokes constant propogation where
* possible. The elaboration generates NetConst objects. I can remove
@@ -34,456 +30,163 @@
* may even be able to replace nets with a new constant.
*/
struct cprop_functor : public functor_t {
unsigned count;
virtual void lpm_add_sub(Design*des, NetAddSub*obj);
virtual void lpm_ff(Design*des, NetFF*obj);
virtual void lpm_logic(Design*des, NetLogic*obj);
virtual void lpm_mux(Design*des, NetMux*obj);
};
void cprop_functor::lpm_add_sub(Design*des, NetAddSub*obj)
static bool is_a_const_node(const NetNode*obj)
{
// For now, only additions are handled.
if (obj->attribute("LPM_Direction") != "ADD")
return;
// If the low bit on the A side is 0, then eliminate it from
// the adder, and pass the B side directly to the
// result. Don't reduce the adder smaller then a 1-bit
// adder. These will be eliminated later.
while ((obj->width() > 1)
&& link_drivers_constant(obj->pin_DataA(0))
&& (driven_value(obj->pin_DataA(0)) == verinum::V0)) {
NetAddSub*tmp = 0;
tmp = new NetAddSub(obj->name(), obj->width()-1);
//connect(tmp->pin_Aclr(), obj->pin_Aclr());
//connect(tmp->pin_Add_Sub(), obj->pin_Add_Sub());
//connect(tmp->pin_Clock(), obj->pin_Clock());
//connect(tmp->pin_Cin(), obj->pin_Cin());
connect(tmp->pin_Cout(), obj->pin_Cout());
//connect(tmp->pin_Overflow(), obj->pin_Overflow());
for (unsigned idx = 0 ; idx < tmp->width() ; idx += 1) {
connect(tmp->pin_DataA(idx), obj->pin_DataA(idx+1));
connect(tmp->pin_DataB(idx), obj->pin_DataB(idx+1));
connect(tmp->pin_Result(idx), obj->pin_Result(idx+1));
}
connect(obj->pin_Result(0), obj->pin_DataB(0));
delete obj;
des->add_node(tmp);
obj = tmp;
count += 1;
}
// Now do the same thing on the B side.
while ((obj->width() > 1)
&& link_drivers_constant(obj->pin_DataB(0))
&& (driven_value(obj->pin_DataB(0)) == verinum::V0)) {
NetAddSub*tmp = 0;
tmp = new NetAddSub(obj->name(), obj->width()-1);
//connect(tmp->pin_Aclr(), obj->pin_Aclr());
//connect(tmp->pin_Add_Sub(), obj->pin_Add_Sub());
//connect(tmp->pin_Clock(), obj->pin_Clock());
//connect(tmp->pin_Cin(), obj->pin_Cin());
connect(tmp->pin_Cout(), obj->pin_Cout());
//connect(tmp->pin_Overflow(), obj->pin_Overflow());
for (unsigned idx = 0 ; idx < tmp->width() ; idx += 1) {
connect(tmp->pin_DataA(idx), obj->pin_DataA(idx+1));
connect(tmp->pin_DataB(idx), obj->pin_DataB(idx+1));
connect(tmp->pin_Result(idx), obj->pin_Result(idx+1));
}
connect(obj->pin_Result(0), obj->pin_DataA(0));
delete obj;
des->add_node(tmp);
obj = tmp;
count += 1;
}
// If the adder is only 1 bit wide, then replace it with the
// simple logic gate.
if (obj->width() == 1) {
NetLogic*tmp;
if (obj->pin_Cout().is_linked()) {
tmp = new NetLogic(obj->scope(),
des->local_symbol(obj->name()), 3,
NetLogic::AND);
connect(tmp->pin(0), obj->pin_Cout());
connect(tmp->pin(1), obj->pin_DataA(0));
connect(tmp->pin(2), obj->pin_DataB(0));
des->add_node(tmp);
}
tmp = new NetLogic(obj->scope(), obj->name(), 3, NetLogic::XOR);
connect(tmp->pin(0), obj->pin_Result(0));
connect(tmp->pin(1), obj->pin_DataA(0));
connect(tmp->pin(2), obj->pin_DataB(0));
delete obj;
des->add_node(tmp);
count += 1;
return;
}
return dynamic_cast<const NetConst*>(obj);
}
void cprop_functor::lpm_ff(Design*des, NetFF*obj)
static bool const_into_xnor(Design*des, NetConst*obj,
NetLogic*log, unsigned pin)
{
// Look for and count unlinked FF outputs. Note that if the
// Data and Q pins are connected together, they can be removed
// from the circuit.
unsigned unlinked_count = 0;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (connected(obj->pin_Data(idx), obj->pin_Q(idx))) {
obj->pin_Data(idx).unlink();
obj->pin_Q(idx).unlink();
assert(pin > 0);
/* if this is the last input pin of the XNOR device, then
the device is simply buffering the constant value. */
if (log->pin_count() == 2) {
cerr << "cprop: delete gate " << log->name() <<
" and propogate " << obj->value() << "." << endl;
assert(pin == 1);
connect(log->pin(0), log->pin(1));
delete log;
return true;
}
/* If this is a constant 0, then replace the gate with one
1-pin smaller. Skip this pin. */
if (obj->value() == verinum::V0) {
cerr << "cprop: disconnect pin " << pin << " from gate "
<< log->name() << "." << endl;
NetLogic*tmp = new NetLogic(log->name(),
log->pin_count()-1,
NetLogic::XNOR);
connect(log->pin(0), tmp->pin(0));
unsigned idx, jdx;
for (idx = 1, jdx = 1 ; idx < log->pin_count() ; idx += 1) {
if (idx == pin) continue;
connect(log->pin(idx), tmp->pin(jdx));
jdx += 1;
}
if (! obj->pin_Q(idx).is_linked())
unlinked_count += 1;
}
// If the entire FF is unlinked, remove the whole thing.
if (unlinked_count == obj->width()) {
delete obj;
count += 1;
return;
}
// If some of the FFs are unconnected, make a new FF array
// that does not include the useless FF devices.
if (unlinked_count > 0) {
NetFF*tmp = new NetFF(obj->name(), obj->width()-unlinked_count);
connect(tmp->pin_Clock(), obj->pin_Clock());
connect(tmp->pin_Enable(), obj->pin_Enable());
connect(tmp->pin_Aload(), obj->pin_Aload());
connect(tmp->pin_Aset(), obj->pin_Aset());
connect(tmp->pin_Aclr(), obj->pin_Aclr());
connect(tmp->pin_Sload(), obj->pin_Sload());
connect(tmp->pin_Sset(), obj->pin_Sset());
connect(tmp->pin_Sclr(), obj->pin_Sclr());
unsigned tidx = 0;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1)
if (obj->pin_Q(idx).is_linked()) {
connect(tmp->pin_Data(tidx), obj->pin_Data(idx));
connect(tmp->pin_Q(tidx), obj->pin_Q(idx));
tidx += 1;
}
assert(tidx == obj->width() - unlinked_count);
delete obj;
delete log;
des->add_node(tmp);
count += 1;
return;
return true;
}
/* If this is a constant 1, then replace the gate with an XOR
that is 1-pin smaller. Removing the constant 1 causes the
sense of the output to change. */
if (obj->value() == verinum::V1) {
cerr << "cprop: disconnect pin " << pin << " from gate "
<< log->name() << "." << endl;
NetLogic*tmp = new NetLogic(log->name(),
log->pin_count()-1,
NetLogic::XOR);
connect(log->pin(0), tmp->pin(0));
unsigned idx, jdx;
for (idx = 1, jdx = 1 ; idx < log->pin_count() ; idx += 1) {
if (idx == pin) continue;
connect(log->pin(idx), tmp->pin(jdx));
jdx += 1;
}
delete log;
des->add_node(tmp);
return true;
}
/* If this is a constant X or Z, then the gate is certain to
generate an X. Replace the gate with a constant X. This may
cause other signals all over to become dangling. */
if ((obj->value() == verinum::Vx) || (obj->value() == verinum::Vz)) {
cerr << "cprop: replace gate " << log->name() << " with "
"a constant X." << endl;
NetConst*tmp = new NetConst(log->name(), verinum::Vx);
connect(log->pin(0), tmp->pin(0));
delete log;
des->add_node(tmp);
return true;
}
return false;
}
void cprop_functor::lpm_logic(Design*des, NetLogic*obj)
static void look_for_core_logic(Design*des, NetConst*obj)
{
switch (obj->type()) {
NetObj*cur = obj;
unsigned pin = 0;
for (obj->pin(0).next_link(cur, pin)
; cur != obj
; cur->pin(pin).next_link(cur, pin)) {
case NetLogic::AND:
// If there is one zero input to an AND gate, we know
// the resulting output is going to be zero and can
// elininate the gate.
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
if (! link_drivers_constant(obj->pin(idx)))
continue;
if (driven_value(obj->pin(idx)) == verinum::V0) {
connect(obj->pin(0), obj->pin(idx));
delete obj;
count += 1;
return;
}
NetLogic*log = dynamic_cast<NetLogic*>(cur);
if (log == 0)
continue;
bool flag = false;
switch (log->type()) {
case NetLogic::XNOR:
flag = const_into_xnor(des, obj, log, pin);
break;
default:
break;
}
// There are no zero constant drivers. If there are any
// non-constant drivers, give up.
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
if (! link_drivers_constant(obj->pin(idx)))
return;
}
// If there are any non-1 values (Vx or Vz) then the
// result is Vx.
for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) {
if (driven_value(obj->pin(idx)) != verinum::V1) {
connect(obj->pin(0), obj->pin(idx));
delete obj;
count += 1;
return;
}
}
// What's left? The inputs are all 1's, return the first
// input as the output value and remove the gate.
connect(obj->pin(0), obj->pin(1));
delete obj;
count += 1;
return;
case NetLogic::XOR: {
unsigned top = obj->pin_count();
unsigned idx = 1;
while (idx < top) {
if (! link_drivers_constant(obj->pin(idx))) {
idx += 1;
continue;
}
if (driven_value(obj->pin(idx)) == verinum::V0) {
obj->pin(idx).unlink();
top -= 1;
if (idx < top) {
connect(obj->pin(idx), obj->pin(top));
obj->pin(top).unlink();
}
} else {
idx += 1;
}
}
if (top == 2) {
NetLogic*tmp = new NetLogic(obj->scope(),
obj->name(), top,
NetLogic::BUF);
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
connect(obj->pin(0), tmp->pin(0));
connect(obj->pin(1), tmp->pin(1));
delete obj;
count += 1;
return;
}
if (top < obj->pin_count()) {
NetLogic*tmp = new NetLogic(obj->scope(),
obj->name(), top,
NetLogic::XOR);
des->add_node(tmp);
tmp->pin(0).drive0(obj->pin(0).drive0());
tmp->pin(0).drive1(obj->pin(0).drive1());
for (unsigned idx = 0 ; idx < top ; idx += 1)
connect(tmp->pin(idx), obj->pin(idx));
delete obj;
count += 1;
return;
}
}
default:
break;
/* If the optimization test tells me that a link was
deleted, restart the scan. */
if (flag) obj->pin(0).next_link(cur, pin);
}
}
/*
* This detects the case where the mux selects between a value an
* Vz. In this case, replace the device with a bufif with the sel
* input used to enable the output.
*/
void cprop_functor::lpm_mux(Design*des, NetMux*obj)
{
if (obj->size() != 2)
return;
if (obj->sel_width() != 1)
return;
/* If the first input is all constant Vz, then replace the
NetMux with an array of BUFIF1 devices, with the enable
connected to the select input. */
bool flag = true;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (! link_drivers_constant(obj->pin_Data(idx, 0))) {
flag = false;
break;
}
if (driven_value(obj->pin_Data(idx, 0)) != verinum::Vz) {
flag = false;
break;
}
}
if (flag) {
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
NetLogic*tmp = new NetLogic(obj->scope(),
des->local_symbol(obj->name()),
3, NetLogic::BUFIF1);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
}
count += 1;
delete obj;
return;
}
/* If instead the second input is all constant Vz, replace the
NetMux with an array of BUFIF0 devices. */
flag = true;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (! link_drivers_constant(obj->pin_Data(idx, 1))) {
flag = false;
break;
}
if (driven_value(obj->pin_Data(idx, 1)) != verinum::Vz) {
flag = false;
break;
}
}
if (flag) {
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
NetLogic*tmp = new NetLogic(obj->scope(),
des->local_symbol(obj->name()),
3, NetLogic::BUFIF0);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,0), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
}
count += 1;
delete obj;
return;
}
}
/*
* This functor looks to see if the constant is connected to nothing
* This function looks to see if the constant is connected to nothing
* but signals. If that is the case, delete the dangling constant and
* the now useless signals. This functor is applied after the regular
* functor to clean up dangling constants that might be left behind.
* the now useless signals.
*/
struct cprop_dc_functor : public functor_t {
virtual void lpm_const(Design*des, NetConst*obj);
};
void cprop_dc_functor::lpm_const(Design*des, NetConst*obj)
static void dangling_const(Design*des, NetConst*obj)
{
// 'bz constant values drive high impedance to whatever is
// connected to it. In otherwords, it is a noop.
{ unsigned tmp = 0;
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
if (obj->value(idx) == verinum::Vz) {
obj->pin(idx).unlink();
tmp += 1;
}
// If there are any links that take input, abort this
// operation.
if (count_inputs(obj->pin(0)) > 0)
return;
if (tmp == obj->pin_count()) {
delete obj;
return;
}
}
// If there are any links that take input, the constant is
// used structurally somewhere.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
if (count_inputs(obj->pin(idx)) > 0)
return;
// Look for signals that have NetESignal nodes attached to
// them. If I find any, this this constant is used by a
// behavioral expression somewhere.
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
Nexus*nex = obj->pin(idx).nexus();
for (Link*clnk = nex->first_nlink()
; clnk ; clnk = clnk->next_nlink()) {
NetObj*cur;
unsigned pin;
clnk->cur_link(cur, pin);
NetNet*tmp = dynamic_cast<NetNet*>(cur);
if (tmp && tmp->get_eref() > 0)
return;
// If there are no other drivers, delete all the signals that
// are also dangling.
if (count_outputs(obj->pin(0)) == 1) {
NetObj*cur;
unsigned pin;
obj->pin(0).next_link(cur, pin);
while (cur != obj) {
cerr << "cprop: delete dangling signal " << cur->name() <<
"." << endl;
delete cur;
obj->pin(0).next_link(cur, pin);
}
}
// Done. Delete me.
delete obj;
}
void cprop(Design*des)
{
// Continually propogate constants until a scan finds nothing
// to do.
cprop_functor prop;
do {
prop.count = 0;
des->functor(&prop);
} while (prop.count > 0);
des->clear_node_marks();
while (NetNode*obj = des->find_node(&is_a_const_node)) {
NetConst*cur = dynamic_cast<NetConst*>(obj);
look_for_core_logic(des, cur);
cur->set_mark();
dangling_const(des, cur);
}
cprop_dc_functor dc;
des->functor(&dc);
}
/*
* $Log: cprop.cc,v $
* Revision 1.17 2000/10/07 19:45:42 steve
* Put logic devices into scopes.
*
* Revision 1.16 2000/10/06 21:26:34 steve
* Eliminate zero inputs to xor.
*
* Revision 1.15 2000/08/02 14:48:01 steve
* use bufif0 if z is in true case of mux.
*
* Revision 1.14 2000/07/25 02:55:13 steve
* Unlink z constants from nets.
*
* Revision 1.13 2000/07/15 05:13:43 steve
* Detect muxing Vz as a bufufN.
*
* Revision 1.12 2000/06/25 19:59:41 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
* Revision 1.11 2000/06/24 22:55:19 steve
* Get rid of useless next_link method.
*
* Revision 1.10 2000/05/14 17:55:04 steve
* Support initialization of FF Q value.
*
* Revision 1.9 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.8 2000/04/28 21:00:28 steve
* Over agressive signal elimination in constant probadation.
*
* Revision 1.7 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.6 2000/01/02 17:56:42 steve
* Do not delete constants that input to exressions.
*
* Revision 1.5 1999/12/30 04:19:12 steve
* Propogate constant 0 in low bits of adders.
*
* Revision 1.4 1999/12/17 06:18:15 steve
* Rewrite the cprop functor to use the functor_t interface.
*
* Revision 1.3 1999/12/17 03:38:46 steve
* NetConst can now hold wide constants.
*
* Revision 1.2 1998/12/02 04:37:13 steve
* Add the nobufz function to eliminate bufz objects,
* Object links are marked with direction,
-54
View File
@@ -1,54 +0,0 @@
This file describes the build procedure under cygwin32 (Windows 95/98/NT/2K)
----------------------------------------------------------------------------
To build using cygwin:
Prerequisites:
o Latest net release (1.1.4) of cygwin (sources.redhat.com/cygwin)
o autoconf version 2.13 (or later) from cygutils (cygutils.netpedia.net)
o cvs (1.10.8 or later) also from cygutils
Procedure:
o Get the source code - see the main icarus verilog page for how to
do this
o cd to the verilog directory
o autoconf
o ./configure
o make
o make install
That's all that's needed. But there're two common problems during
the make phase. All steps are in the verilog directory.
1.
If gcc dies saying virtual memory exhausted while compiling parse.c
then recompile with -O1 or without -O flag and do these steps to
continue
o c++ -DHAVE_GETOPT_H=1 -DUSE_LIBVPIP=1 -g -I. -MD -c parse.cc -o parse.o
o mv parse.d dep/parse.d
o make
2.
If gcc dies in the vpi directory while compiling vpi_systask.c with the
error, conflicting types for `_cygwin_dll_entry', then fix the line in
/usr/include/cygwin/cygwin_dll.h. Change the line:
int WINAPI _cygwin_dll_entry (HANDLE h, DWORD reason, void *ptr); \
to
int WINAPI _cygwin_dll_entry (HINSTANCE h, DWORD reason, void *ptr); \
Note the change from HANDLE to HINSTANCE. Then do
o make
To build your own extensions - just include vpi_user.h and link with
a command like this:
$(CC) -shared -o <dllname> <objects> -Wl,--enable-auto-image-base -L../vvm -lvvm -lvpip
- Venkat Iyer <[email protected]>
+422 -376
View File
File diff suppressed because it is too large Load Diff
-6
View File
@@ -1,6 +0,0 @@
Makefile
parse.c
parse.h
parse.output
lexor.c
iverilog
-90
View File
@@ -1,90 +0,0 @@
#
# 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.1 2000/10/08 22:36:56 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
mandir = @mandir@
dllib=@DLLIB@
rdynamic=@rdynamic@
CC = @CC@
CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CPPFLAGS = @CPPFLAGS@ @DEFS@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
all: iverilog@EXEEXT@
clean:
rm -f *.o lexor.c parse.c parse.h parse.output
O = main.o build_string.o lexor.o parse.o
iverilog@EXEEXT@: $O
$(CC) $(LDFLAGS) $O -o iverilog@EXEEXT@
lexor.c: lexor.lex
flex -s -olexor.c lexor.lex
parse.h parse.c: parse.y
bison --verbose -t -d parse.y -o parse.c
main.o: main.c globals.h
$(CC) $(CPPFLAGS) -c -DCXX='"@CXX@"' -DIVL_ROOT='"@libdir@/ivl"' -DIVL_INC='"@includedir@"' -DIVL_LIB='"@libdir@"' -DRDYNAMIC=\"$(rdynamic)\" -DDLLIB='"@DLLIB@"' main.c
build_string.o: build_string.c globals.h
lexor.o: lexor.c parse.h globals.h
parse.o: parse.c
install: all installdirs $(bindir)/iverilog@EXEEXT@ $(mandir)/man1/iverilog.1
$(bindir)/iverilog@EXEEXT@: ./iverilog@EXEEXT@
$(INSTALL_PROGRAM) ./iverilog@EXEEXT@ $(bindir)/iverilog@EXEEXT@
$(mandir)/man1/iverilog.1: $(srcdir)/iverilog.man
$(INSTALL_DATA) $(srcdir)/iverilog.man $(mandir)/man1/iverilog.1
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(bindir) $(mandir)/man1
uninstall:
rm -f $(bindir)/iverilog@EXEEXT@
rm -f $(mandir)/man1/iverilog.1
-119
View File
@@ -1,119 +0,0 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: build_string.c,v 1.1 2000/10/08 22:36:56 steve Exp $"
#endif
# include "globals.h"
# include <string.h>
# include <assert.h>
int build_string(char*output, size_t olen, const char*pattern)
{
char tmp_buf[1024];
char*output_save = output;
while (*pattern) {
if (*pattern == '%') {
pattern += 1;
switch (*pattern) {
case 0:
break;
case '%':
*output++ = '%';
break;
case '?': {
const char*tail;
pattern += 1;
assert(*pattern);
tail = strchr(pattern+1, ';');
assert(tail);
strncpy(tmp_buf, pattern+1, tail-pattern-1);
tmp_buf[tail-pattern-1] = 0;
if (((*pattern == 's') && start)
|| ((*pattern == 'N') && npath)
|| ((*pattern == 'T') && mtm)) {
int rc = build_string(output, olen,
tmp_buf);
output += rc;
olen -= rc;
}
pattern = tail;
break;
}
case 'B':
strcpy(output, base);
output += strlen(base);
olen -= strlen(base);
break;
case 'N':
if (npath) {
strcpy(output, npath);
output += strlen(npath);
olen -= strlen(npath);
}
break;
case 's':
if (start) {
strcpy(output, start);
output += strlen(start);
olen -= strlen(start);
}
break;
case 'T':
if (mtm) {
strcpy(output, mtm);
output += strlen(mtm);
olen -= strlen(mtm);
}
break;
case 't':
strcpy(output, targ);
output += strlen(targ);
olen -= strlen(targ);
break;
}
pattern += 1;
} else {
*output++ = *pattern++;
olen -= 1;
}
}
*output = 0;
return output-output_save;
}
/*
* $Log: build_string.c,v $
* Revision 1.1 2000/10/08 22:36:56 steve
* iverilog with an iverilog.conf configuration file.
*
*/
-52
View File
@@ -1,52 +0,0 @@
#ifndef __globals_H
#define __globals_H
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: globals.h,v 1.1 2000/10/08 22:36:56 steve Exp $"
#endif
# include <stddef.h>
/* This is the base (i.e. -B<value>) of the Icarus Verilog files. */
extern const char*base;
/* This is the optional -Tmin|typ|max setting. */
extern const char*mtm;
/* Ths is the optional -N<path> value, if one was supplied. */
extern const char*npath;
/* This pointer is set if there was a -s<value> parameter. */
extern const char*start;
/* This is the name of the selected target. */
extern const char*targ;
extern const char*lookup_pattern(const char*key);
extern int build_string(char*out, size_t olen, const char*pattern);
/*
* $Log: globals.h,v $
* Revision 1.1 2000/10/08 22:36:56 steve
* iverilog with an iverilog.conf configuration file.
*
*/
#endif
-169
View File
@@ -1,169 +0,0 @@
.TH iverilog 1 "$Date: 2000/10/08 22:36:56 $" Version "$Date: 2000/10/08 22:36:56 $"
.SH NAME
iverilog - Icarus Verilog compiler
.SH SYNOPSIS
.B iverilog
[-ESv] [-Dmacro[=defn]] [-fflag=value] [-Iincludepath] [-mmodule] [-Nfile] [-ooutputfilename] [-s topmodule] [-ttype] [-Tmin/typ/max] [-Wclass] sourcefile[s]
.SH DESCRIPTION
.PP
\fIiverilog\fP is a compiler that translates Verilog source code into
executable programs for simulation, or other netlist formats for
further processing. The currenty supported targets are \fIvvm\fP (for
executable simulation) and \fIxnf\fP for synthesis. Other target
types are added as code generators are implemented.
.SH OPTIONS
.l
\fIiverilog\fP accepts the following options:
.TP 8
.B -B\fIbase\fP
The \fIiverilog\fP program uses external programs to preprocess and
compile the verilog source. Normally, the path used to locate these
tools is built into the \fIiverilog\fP program. However, the \fB-B\fP
switch allows the user to select a different set of programs. The path
given is used to locate \fIivlpp\fP, \fIivl\fP and the VPI modules.
.TP 8
.B -D\fImacro\fP
Defines macro \fImacro\fP with the string `1' as its definition. This
form is normally only used to trigger ifdef conditionals in the
Verilog source.
.TP 8
.B -D\fImacro=defn\fP
Defines macro \fImacro\fP as \fIdefn\fP.
.TP 8
.B -E
Preprocess the Verilog source, but do not compile it. The output file
is the Verilog input, but with file inclusions and macro references
expanded and removed. This is useful, for example, to preprocess
verilog source for use by other compilers.
.TP 8
.B -f\fIflag=value\fP
Assign a value to a target specific flag. The \fB-f\fP switch may be
used as often as necessary to specify all the desired flags. The flags
that are used depend on the target that is selected, and are described
in target specific documentation. Flags that are not used are ignored.
.TP 8
.B -I\fIincludedir\fP
Append directory \fIincludepdir\fP to list of directoriess searched
for Verilog include files. The \fB-I\fP switch may be used many times
to specify several directories to search, the directories are searched
in the order they appear on the command line.
.TP 8
.B -m\fImodule\fP
Add this module to the list of VPI modules to be loaded by the
simulation. Many modules can be specified, and all will be loaded, in
the order specified.
.TP 8
.B -N\fIpath\fP
This is used for debugging the compiler proper. Dump the final netlist
form of the design to the specified file. It otherwise does not affect
operation of the compiler. The dump happens after the design is
elaborated and optimized.
.TP 8
.B -o \fIfilename\fP
Place output in the file \fIfilename\fP. If no output file name is
specified, \fIiverilog\fP uses the default name \fBa.out\fP.
.TP 8
.B -S
Synthesize. Normally, if the target can accept behavioral
descriptions the compiler will leave processes in behavioral
form. The \fB-S\fP switch causes the compiler to perform synthesis
even if it is not necessary for the target. If the target type is a
netlist format, the \fB-S\fP switch is unnecessary and has no effect.
.TP 8
.B -s \fItopmodule\fP
Specify the top level module to elaborate. Icarus Verilog will by default
choose the only module that has no ports. However, this simplistic
heuristic is often not sufficient, and sometimes not what is wanted
anyhow.
.TP 8
.B -T\fImin|typ|max\fP
Use this switch to select min, typ or max times from min:typ:max
expressions. Normally, the compiler will simply use the typ value from
these expressions (with a warning) but this switch will tell the
compiler explicitly which value to use. This will suppress the
warning that the compiler is making a choice.
.TP 8
.B -t\fItarget\fP
Use this switch to specify the target output format. See the
\fBTARGETS\fP section below for a list of valid output formats.
.TP 8
.B -v
Turn on verbose messages. This will print the command lines that are
executed to perform the actual compilation, along with version
information from the various components.
.TP 8
.B -W\fIclass\fP
Turn on different classes of warnings. See the \fBWARNING TYPES\fP
section below for desctriptions of the different warning groups. If
multiple \fB-W\fP switches are used, the warning set is the union of
all the requested classes.
.SH TARGETS
The Icarus Verilog compiler supports a variety of targets, for
different purposes, and the \fB-t\fP switch is used to select the
desired target.
.TP 8
.B null
The null target causes no code to be generated. It is useful for
checking the syntax of the Verilog source.
.TP 8
.B vvm
This is the default. The target is an executable program that uses the
vvm simulation runtime. The compiler actually generates C++ code, then
compiles and links that code to make the output executable.
.TP 8
.B xnf
This is the Xilinx Netlist Format used by many tools for placing
devices in FPGAs or other programmable devices. The Icarus Verilog XNF
code generator can generate complete designs or XNF macros that can be
imported into larger designs by other tools.
.SH "WARNING TYPES"
These are the types of warnings that can be selected by the \fB-W\fP
switch.
.TP 8
.B all
This enables all supported warning categories.
.TP 8
.B implicit
This enables warnings for creation of implicit declarations. For
example, if a scaler wire X is used but not declared in the Verilog
source, this will print a warning at its first use.
.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 a.out:
verilog hello.v
To compile hello.v to an executable file called hello:
verilog -o hello hello.v
To compile hello.v to a file in XNF-format called hello.xnf
verilog -txnf -ohello.xnf hello.v
.SH "AUTHOR"
.nf
Steve Williams ([email protected])
.SH SEE ALSO
.BR "<http://www.icarus.com/eda/verilog/>"
.SH COPYRIGHT
.nf
Copyright \(co 2000 Stephen Williams
This document can be freely redistributed according to the terms of the
GNU General Public License version 2.0
-73
View File
@@ -1,73 +0,0 @@
%{
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: lexor.lex,v 1.1 2000/10/08 22:36:56 steve Exp $"
#endif
# include <string.h>
# include "parse.h"
%}
%x CTOKENS
%x PATTERN
%%
"#".* { /* eat comments */; }
"\n" { /* eat line-ends */; }
"[" { BEGIN(CTOKENS); return '['; }
<CTOKENS>"]" { BEGIN(0); return ']'; }
<CTOKENS>[ \t\b]+ { /* skip white space */; }
<CTOKENS>"-S" { return CT_S; }
<CTOKENS>"-t"[a-zA-Z0-9]+ {
yylval.text = strdup(yytext+2);
return CT_t; }
"<"[^>]*">" {
BEGIN(PATTERN);
yylval.text = strdup(yytext);
return PATTERN_NAME; }
<PATTERN>.* {
BEGIN(0);
yylval.text = strdup(yytext);
return PATTERN_TEXT; }
. { fprintf(stderr, "driver lexor: Unmatched character: %c\n", yytext[0]); }
%%
void reset_lexor(FILE*fd)
{
yyrestart(fd);
}
int yywrap()
{
return 1;
}
-502
View File
@@ -1,502 +0,0 @@
/*
* Copyright (c) 2000 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: main.c,v 1.1 2000/10/08 22:36:56 steve Exp $"
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
#if HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifndef IVL_ROOT
# define IVL_ROOT "."
#endif
#ifndef RDYNAMIC
# define RDYNAMIC "-rdynamic"
#endif
#ifdef USE_LIBVPIP
# define LIBVPIP "-lvpip"
#else
# define LIBVPIP ""
#endif
# include "globals.h"
const char*base = IVL_ROOT;
const char*mtm = 0;
const char*opath = "a.out";
const char*npath = 0;
const char*targ = "vvm";
const char*start = 0;
char warning_flags[16] = "";
char*inc_list = 0;
char*def_list = 0;
char*mod_list = 0;
char*f_list = 0;
int synth_flag = 0;
int verbose_flag = 0;
char tmp[4096];
/*
* This is the default target type. It looks up the bits that are
* needed to run the command from the configuration file (which is
* already parsed for us) so we can handle must of the generic cases.
*/
static int t_default(char*cmd, unsigned ncmd)
{
int rc;
const char*pattern;
pattern = lookup_pattern("<ivl>");
if (pattern == 0) {
fprintf(stderr, "No such target: %s\n", targ);
return -1;
}
tmp[0] = ' ';
tmp[1] = '|';
tmp[2] = ' ';
rc = build_string(tmp+3, sizeof tmp - 3, pattern);
cmd = realloc(cmd, ncmd+3+rc+1);
strcpy(cmd+ncmd, tmp);
if (verbose_flag)
printf("translate: %s\n", cmd);
rc = system(cmd);
if (rc != 0) {
if (WIFEXITED(rc))
return WEXITSTATUS(rc);
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
}
return 0;
}
/*
* This function handles the vvm target. After preprocessing, run the
* ivl translator to get C++, then run g++ to make an executable
* program out of that.
*/
static int t_vvm(char*cmd, unsigned ncmd)
{
int rc;
sprintf(tmp, " | %s/ivl %s -o %s.cc -tvvm -Fcprop %s -Fnodangle"
" -fVPI_MODULE_PATH=%s", base, warning_flags, opath,
synth_flag?"-Fsynth -Fsyn-rules":"", base);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
if (f_list) {
rc = strlen(f_list);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, f_list);
ncmd += rc;
}
if (mod_list) {
rc = strlen(mod_list);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, mod_list);
ncmd += rc;
}
if (mtm) {
sprintf(tmp, " -T%s", mtm);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
}
if (npath) {
sprintf(tmp, " -N%s", npath);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
}
if (start) {
sprintf(tmp, " -s%s", start);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
}
sprintf(tmp, " -- -");
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
if (verbose_flag)
printf("translate: %s\n", cmd);
rc = system(cmd);
if (rc != 0) {
if (WIFEXITED(rc)) {
fprintf(stderr, "errors translating Verilog program.\n");
return WEXITSTATUS(rc);
} else {
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
}
}
sprintf(tmp, "%s -O " RDYNAMIC " -fno-exceptions -o %s -I%s "
"-L%s %s.cc -lvvm " LIBVPIP "%s", CXX, opath, IVL_INC, IVL_LIB,
opath, DLLIB);
if (verbose_flag)
printf("compile: %s\n", tmp);
rc = system(tmp);
if (rc != 0) {
if (WIFEXITED(rc)) {
fprintf(stderr, "errors compiling translated program.\n");
return WEXITSTATUS(rc);
} else {
fprintf(stderr, "Command signaled: %s\n", tmp);
return -1;
}
}
sprintf(tmp, "%s.cc", opath);
unlink(tmp);
return 0;
}
static int t_xnf(char*cmd, unsigned ncmd)
{
int rc;
sprintf(tmp, " | %s/ivl %s -o %s -txnf -Fcprop -Fsynth -Fsyn-rules "
"-Fnodangle -Fxnfio", base, warning_flags, opath);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
if (f_list) {
rc = strlen(f_list);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, f_list);
ncmd += rc;
}
if (mtm) {
sprintf(tmp, " -T%s", mtm);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
}
if (npath) {
sprintf(tmp, " -N%s", npath);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
}
if (start) {
sprintf(tmp, " -s%s", start);
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
}
sprintf(tmp, " -- -");
rc = strlen(tmp);
cmd = realloc(cmd, ncmd+rc+1);
strcpy(cmd+ncmd, tmp);
ncmd += rc;
if (verbose_flag)
printf("translate: %s\n", cmd);
rc = system(cmd);
if (rc != 0) {
if (WIFEXITED(rc)) {
fprintf(stderr, "errors translating Verilog program.\n");
return WEXITSTATUS(rc);
}
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
}
return 0;
}
static void process_warning_switch(const char*name)
{
if (warning_flags[0] == 0)
strcpy(warning_flags, "-W");
if (strcmp(name,"all") == 0) {
strcat(warning_flags, "i");
} else if (strcmp(name,"implicit") == 0) {
if (! strchr(warning_flags+2, 'i'))
strcat(warning_flags, "i");
}
}
int main(int argc, char **argv)
{
const char*config_path = 0;
char*cmd;
unsigned ncmd;
int e_flag = 0;
int opt, idx;
char*cp;
while ((opt = getopt(argc, argv, "B:C:D:Ef:I:m:N::o:Ss:T:t:vW:")) != EOF) {
switch (opt) {
case 'B':
base = optarg;
break;
case 'C':
config_path = optarg;
break;
case 'D':
if (def_list == 0) {
def_list = malloc(strlen(" -D")+strlen(optarg)+1);
strcpy(def_list, " -D");
strcat(def_list, optarg);
} else {
def_list = realloc(def_list, strlen(def_list)
+ strlen(" -D")
+ strlen(optarg) + 1);
strcat(def_list, " -D");
strcat(def_list, optarg);
}
break;
case 'E':
e_flag = 1;
break;
case 'f':
if (f_list == 0) {
f_list = malloc(strlen(" -f")+strlen(optarg)+1);
strcpy(f_list, " -f");
strcat(f_list, optarg);
} else {
f_list = realloc(f_list, strlen(f_list) +
strlen(" -f") +
strlen(optarg) + 1);
strcat(f_list, " -f");
strcat(f_list, optarg);
}
break;
case 'I':
if (inc_list == 0) {
inc_list = malloc(strlen(" -I")+strlen(optarg)+1);
strcpy(inc_list, " -I");
strcat(inc_list, optarg);
} else {
inc_list = realloc(inc_list, strlen(inc_list)
+ strlen(" -I")
+ strlen(optarg) + 1);
strcat(inc_list, " -I");
strcat(inc_list, optarg);
}
break;
case 'm':
if (mod_list == 0) {
mod_list = malloc(strlen(" -m")+strlen(optarg)+1);
strcpy(mod_list, " -m");
strcat(mod_list, optarg);
} else {
mod_list = realloc(mod_list, strlen(mod_list)
+ strlen(" -m")
+ strlen(optarg) + 1);
strcat(mod_list, " -m");
strcat(mod_list, optarg);
}
break;
case 'N':
npath = optarg;
break;
case 'o':
opath = optarg;
break;
case 'S':
synth_flag = 1;
break;
case 's':
start = optarg;
break;
case 'T':
if (strcmp(optarg,"min") == 0) {
mtm = "min";
} else if (strcmp(optarg,"typ") == 0) {
mtm = "typ";
} else if (strcmp(optarg,"max") == 0) {
mtm = "max";
} else {
fprintf(stderr, "%s: invalid -T%s argument\n",
argv[0], optarg);
return 1;
}
break;
case 't':
targ = optarg;
break;
case 'v':
verbose_flag = 1;
break;
case 'W':
process_warning_switch(optarg);
break;
case '?':
default:
return 1;
}
}
if (optind == argc) {
fprintf(stderr, "%s: No input files.\n", argv[0]);
return 1;
}
/* Load the iverilog.conf file to get our substitution
strings. */
{ char path[1024];
FILE*fd;
if (config_path) {
strcpy(path, config_path);
} else {
sprintf(path, "%s/iverilog.conf", base);
}
fd = fopen(path, "r");
reset_lexor(fd);
yyparse();
}
/* Start building the preprocess command line. */
sprintf(tmp, "%s/ivlpp %s%s", base,
verbose_flag?" -v":"",
e_flag?"":" -L");
ncmd = strlen(tmp);
cmd = malloc(ncmd + 1);
strcpy(cmd, tmp);
if (inc_list) {
cmd = realloc(cmd, ncmd + strlen(inc_list) + 1);
strcat(cmd, inc_list);
ncmd += strlen(inc_list);
}
if (def_list) {
cmd = realloc(cmd, ncmd + strlen(def_list) + 1);
strcat(cmd, def_list);
ncmd += strlen(def_list);
}
/* Add all the verilog source files to the preprocess command line. */
for (idx = optind ; idx < argc ; idx += 1) {
sprintf(tmp, " %s", argv[idx]);
cmd = realloc(cmd, ncmd+strlen(tmp)+1);
strcpy(cmd+ncmd, tmp);
ncmd += strlen(tmp);
}
/* If the -E flag was given on the command line, then all we
do is run the preprocessor and put the output where the
user wants it. */
if (e_flag) {
int rc;
if (strcmp(opath,"-") != 0) {
sprintf(tmp, " > %s", opath);
cmd = realloc(cmd, ncmd+strlen(tmp)+1);
strcpy(cmd+ncmd, tmp);
ncmd += strlen(tmp);
}
if (verbose_flag)
printf("preprocess: %s\n", cmd);
rc = system(cmd);
if (rc != 0) {
if (WIFEXITED(rc)) {
fprintf(stderr, "errors preprocessing Verilog program.\n");
return WEXITSTATUS(rc);
}
fprintf(stderr, "Command signaled: %s\n", cmd);
return -1;
}
return 0;
}
if (strcmp(targ,"vvm") == 0)
return t_vvm(cmd, ncmd);
else if (strcmp(targ,"xnf") == 0)
return t_xnf(cmd, ncmd);
else {
return t_default(cmd, ncmd);
}
return 0;
}
/*
* $Log: main.c,v $
* Revision 1.1 2000/10/08 22:36:56 steve
* iverilog with an iverilog.conf configuration file.
*
*/
-158
View File
@@ -1,158 +0,0 @@
%{
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: parse.y,v 1.1 2000/10/08 22:36:56 steve Exp $"
#endif
# include <stdio.h>
# include <malloc.h>
# include "globals.h"
void yyerror(const char*);
enum drive_code_t {
CODE_S,
CODE_t,
};
struct drive_cond {
struct drive_cond*next;
enum drive_code_t code;
char* text;
};
static struct drive_cond *cur_cond = 0;
static void add_cond(enum drive_code_t code, char*text)
{
struct drive_cond*tmp;
tmp = calloc(1, sizeof(struct drive_cond));
tmp->code = code;
tmp->text = text;
tmp->next = cur_cond;
cur_cond = tmp;
}
struct drive_pattern {
struct drive_pattern*next;
char*name;
char*text;
struct drive_cond*cond;
};
static struct drive_pattern *patterns = 0;
static struct drive_pattern *plast = 0;
static void add_pattern(char*name, char*text)
{
struct drive_pattern*tmp;
tmp = calloc(1, sizeof(struct drive_pattern));
tmp->name = name;
tmp->text = text;
tmp->cond = cur_cond;
tmp->next = 0;
if (plast) {
plast->next = tmp;
plast = tmp;
} else {
patterns = tmp;
plast = tmp;
}
}
const char*lookup_pattern(const char*key)
{
struct drive_pattern*cur;
struct drive_cond*cc;
for (cur = patterns ; cur ; cur = cur->next) {
if (strcmp(key, cur->name) != 0)
continue;
for (cc = cur->cond ; cc ; cc = cc->next) {
switch (cc->code) {
case CODE_t:
if (strcmp(targ, cc->text) == 0)
continue;
break;
}
break;
}
if (cc) continue;
return cur->text;
}
return 0;
}
%}
%union {
char*text;
};
%token <text> PATTERN_NAME PATTERN_TEXT
%token <text> CT_t
%token CT_S
%%
start: section_list
section_list
: section
| section_list section
;
section : '[' ctoken_list ']' pattern_list { cur_cond = 0; } ;
ctoken_list
: ctoken
| ctoken_list ctoken
;
ctoken : CT_S { add_cond(CODE_S, 0); }
| CT_t { add_cond(CODE_t, $1); }
;
pattern_list
: pattern
| pattern_list pattern
;
pattern : PATTERN_NAME PATTERN_TEXT
{ add_pattern($1, $2); }
;
%%
void yyerror(const char*msg)
{
fprintf(stderr, "%s\n", msg);
}
+2 -22
View File
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: dup_expr.cc,v 1.4 2000/05/07 18:20:07 steve Exp $"
#if !defined(WINNT)
#ident "$Id: dup_expr.cc,v 1.1 1999/11/27 19:07:57 steve Exp $"
#endif
# include "netlist.h"
@@ -29,28 +29,8 @@ NetEScope* NetEScope::dup_expr() const
return 0;
}
NetESFunc* NetESFunc::dup_expr() const
{
NetESFunc*tmp = new NetESFunc(name_, expr_width(), nparms());
for (unsigned idx = 0 ; idx < nparms() ; idx += 1)
tmp->parm(idx, tmp->parm(idx)->dup_expr());
return tmp;
}
/*
* $Log: dup_expr.cc,v $
* Revision 1.4 2000/05/07 18:20:07 steve
* Import MCD support from Stephen Tell, and add
* system function parameter support to the IVL core.
*
* Revision 1.3 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.2 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
+54 -295
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2000 Stephen Williams ([email protected])
* 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
@@ -16,30 +16,24 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: elab_expr.cc,v 1.29 2000/09/26 05:05:58 steve Exp $"
#if !defined(WINNT)
#ident "$Id: elab_expr.cc,v 1.12 1999/11/30 04:54:01 steve Exp $"
#endif
# include "pform.h"
# include "netlist.h"
NetExpr* PExpr::elaborate_expr(Design*des, NetScope*) const
{
cerr << get_line() << ": I do not know how to elaborate expression: "
<< *this << endl;
return 0;
}
/*
* Elaborate binary expressions. This involves elaborating the left
* and right sides, and creating one of a variety of different NetExpr
* types.
*/
NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope) const
NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
{
NetExpr*lp = left_->elaborate_expr(des, scope);
NetExpr*rp = right_->elaborate_expr(des, scope);
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;
@@ -61,21 +55,7 @@ NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope) const
}
}
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp);
return tmp;
}
/*
* This is common elaboration of the operator. It presumes that the
* operands are elaborated as necessary, and all I need to do is make
* the correct NetEBinary object and connect the parameters.
*/
NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
NetExpr*lp, NetExpr*rp) const
{
bool flag;
NetEBinary*tmp;
switch (op_) {
default:
tmp = new NetEBinary(op_, lp, rp);
@@ -88,17 +68,6 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
tmp->set_line(*this);
break;
case '*':
tmp = new NetEBMult(op_, lp, rp);
tmp->set_line(*this);
break;
case '/':
case '%':
tmp = new NetEBDiv(op_, lp, rp);
tmp->set_line(*this);
break;
case 'l':
case 'r':
tmp = new NetEBShift(op_, lp, rp);
@@ -142,59 +111,38 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
return tmp;
}
NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope) const
NetESFunc* PECallFunction::elaborate_sfunc_(Design*des, const string&path) const
{
unsigned wid = 32;
if (name_ == "$time")
wid = 64;
NetESFunc*fun = new NetESFunc(name_, wid, parms_.count());
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
PExpr*expr = parms_[idx];
NetExpr*tmp = expr->elaborate_expr(des, scope);
fun->parm(idx, tmp);
}
return fun;
cerr << get_line() << ": sorry: system functions not supported."
<< endl;
des->errors += 1;
return 0;
}
NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope) const
NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
{
if (name_[0] == '$')
return elaborate_sfunc_(des, scope);
return elaborate_sfunc_(des, path);
NetFuncDef*def = des->find_function(scope, name_);
string myname = path+"."+name_;
NetFuncDef*def = des->find_function(path, name_);
if (def == 0) {
cerr << get_line() << ": error: No function " << name_ <<
" in this context (" << scope->name() << ")." << endl;
" in this context (" << path << ")." << endl;
des->errors += 1;
return 0;
}
assert(def);
NetScope*dscope = des->find_scope(def->name());
assert(dscope);
svector<NetExpr*> parms (parms_.count());
/* Elaborate the input expressions for the function. This is
done in the scope of the function call, and not the scope
of the function being called. The scope of the called
function is elaborated when the definition is elaborated. */
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
NetExpr*tmp = parms_[idx]->elaborate_expr(des, scope);
NetExpr*tmp = parms_[idx]->elaborate_expr(des, myname);
parms[idx] = tmp;
}
/* Look for the return value signal for the called
function. This return value is a magic signal in the scope
of the function, that has the name of the function. The
function code assigns to this signal to return a value. */
NetNet*res = des->find_signal(dscope, name_);
/* 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 " <<
@@ -211,66 +159,22 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope) const
}
NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope) const
NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
{
unsigned repeat = 1;
// System identifiers show up in the netlist as identifiers.
if (text_[0] == '$')
return new NetEIdent(text_, 64);
/* If there is a repeat expression, then evaluate the constant
value and set the repeat count. */
if (repeat_) {
verinum*vrep = repeat_->eval_const(des, scope->name());
if (vrep == 0) {
cerr << get_line() << ": error: "
"concatenation repeat expression cannot be evaluated."
<< endl;
des->errors += 1;
return 0;
}
repeat = vrep->as_ulong();
delete vrep;
}
/* Make the empty concat expression. */
NetEConcat*tmp = new NetEConcat(parms_.count(), repeat);
tmp->set_line(*this);
/* Elaborate all the parameters and attach them to the concat node. */
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
assert(parms_[idx]);
NetExpr*ex = parms_[idx]->elaborate_expr(des, scope);
if (ex == 0) continue;
ex->set_line(*parms_[idx]);
if (! ex->has_width()) {
cerr << ex->get_line() << ": error: operand of "
<< "concatenation has indefinite width: "
<< *ex << endl;
des->errors += 1;
}
tmp->set(idx, ex);
}
return tmp;
}
NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
{
assert(text_[0] != '$');
//string name = path+"."+text_;
assert(scope);
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(scope, text_)) {
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, scope, text_);
tmp = new NetEParam(des, path, text_);
tmp->set_line(*this);
return tmp;
@@ -278,16 +182,15 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
// If the identifier names a signal (a register or wire)
// then create a NetESignal node to handle it.
if (NetNet*net = des->find_signal(scope, text_)) {
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. The lsb_ and msb_ expressions are from
// the foo[msb:lsb] expression in the original.
// selected bits.
if (lsb_) {
assert(msb_);
verinum*lsn = lsb_->eval_const(des, scope->name());
verinum*msn = msb_->eval_const(des, scope->name());
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 "
@@ -298,50 +201,14 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
assert(lsn);
assert(msn);
/* The indices of part selects are signed
integers, so allow negative values. However,
the width that they represent is
unsigned. Remember that any order is possible,
i.e. [1:0], [-4,6], etc. */
long lsv = lsn->as_long();
long msv = msn->as_long();
unsigned long lsv = lsn->as_ulong();
unsigned long msv = msn->as_ulong();
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
if (wid > net->pin_count()) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of range."
<< endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
assert(wid <= net->pin_count());
assert(net->sb_to_idx(msv) >= net->sb_to_idx(lsv));
if (net->sb_to_idx(msv) < net->sb_to_idx(lsv)) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of order."
<< endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
if (net->sb_to_idx(msv) >= net->pin_count()) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of range."
<< endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
string tname = des->local_symbol(scope->name());
NetTmp*tsig = new NetTmp(scope, tname, wid);
string tname = des->local_symbol(path);
NetTmp*tsig = new NetTmp(tname, wid);
// Connect the pins from the lsb up to the msb.
unsigned off = net->sb_to_idx(lsv);
@@ -351,6 +218,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
NetESignal*tmp = new NetESignal(tsig);
tmp->set_line(*this);
des->add_signal(tsig);
return tmp;
}
@@ -358,25 +226,17 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
// 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, scope->name()))) {
if (msb_ && (msn = msb_->eval_const(des, path))) {
assert(idx_ == 0);
unsigned long msv = msn->as_ulong();
unsigned idx = net->sb_to_idx(msv);
if (idx >= net->pin_count()) {
cerr << get_line() << ": internal error: "
<< "bit " << msv << " out of range of net "
<< net->name() << "[" << net->msb()
<< ":" << net->lsb() << "]." << endl;
return 0;
}
string tname = des->local_symbol(scope->name());
NetTmp*tsig = new NetTmp(scope, tname);
connect(tsig->pin(0), net->pin(idx));
string tname = des->local_symbol(path);
NetTmp*tsig = new NetTmp(tname);
connect(tsig->pin(0), net->pin(msv));
NetESignal*tmp = new NetESignal(tsig);
tmp->set_line(*this);
des->add_signal(tsig);
return tmp;
}
@@ -386,7 +246,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
// 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, scope);
NetExpr*ex = msb_->elaborate_expr(des, path);
NetESubSignal*ss = new NetESubSignal(node, ex);
ss->set_line(*this);
return ss;
@@ -401,23 +261,17 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
// If the identifier names a memory, then this is a
// memory reference and I must generate a NetEMemory
// object to handle it.
if (NetMemory*mem = des->find_memory(scope, text_)) {
if (NetMemory*mem = des->find_memory(path, text_)) {
if (msb_ == 0) {
NetEMemory*node = new NetEMemory(mem);
node->set_line(*this);
return node;
}
assert(msb_ != 0);
if (lsb_) {
cerr << get_line() << ": error: part select of a memory: "
<< mem->name() << endl;
cerr << get_line() << ": error: Memory ``" << name <<
"'' referenced without an index expression." << endl;
des->errors += 1;
return 0;
}
assert(msb_ != 0);
assert(lsb_ == 0);
assert(idx_ == 0);
NetExpr*i = msb_->elaborate_expr(des, scope);
NetExpr*i = msb_->elaborate_expr(des, path);
if (msb_ && i == 0) {
cerr << get_line() << ": error: Unable to exaborate "
"index expression `" << *msb_ << "'" << endl;
@@ -439,48 +293,33 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope) const
// I cannot interpret this identifier. Error message.
cerr << get_line() << ": error: Unable to bind wire/reg/memory "
"`" << text_ << "' in `" << scope->name() << "'" << endl;
"`" << path << "." << text_ << "'" << endl;
des->errors += 1;
return 0;
}
NetEConst* PENumber::elaborate_expr(Design*des, NetScope*) const
{
assert(value_);
NetEConst*tmp = new NetEConst(*value_);
tmp->set_line(*this);
return tmp;
}
NetEConst* PEString::elaborate_expr(Design*des, NetScope*) const
{
NetEConst*tmp = new NetEConst(value());
tmp->set_line(*this);
return tmp;
}
/*
* 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.
*/
NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope) const
NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const
{
assert(expr_);
assert(tru_);
assert(fal_);
NetExpr*con = expr_->elaborate_expr(des, scope);
NetExpr*con = expr_->elaborate_expr(des, path);
if (con == 0)
return 0;
NetExpr*tru = tru_->elaborate_expr(des, scope);
NetExpr*tru = tru_->elaborate_expr(des, path);
if (tru == 0) {
delete con;
return 0;
}
NetExpr*fal = fal_->elaborate_expr(des, scope);
NetExpr*fal = fal_->elaborate_expr(des, path);
if (fal == 0) {
delete con;
delete tru;
@@ -491,88 +330,8 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope) const
return res;
}
NetEUnary* PEUnary::elaborate_expr(Design*des, NetScope*scope) const
{
NetExpr*ip = expr_->elaborate_expr(des, scope);
if (ip == 0) return 0;
/* Should we evaluate expressions ahead of time,
* just like in PEBinary::elaborate_expr() ?
*/
NetEUnary*tmp;
switch (op_) {
default:
tmp = new NetEUnary(op_, ip);
tmp->set_line(*this);
break;
case '~':
tmp = new NetEUBits(op_, ip);
tmp->set_line(*this);
break;
}
return tmp;
}
/*
* $Log: elab_expr.cc,v $
* Revision 1.29 2000/09/26 05:05:58 steve
* Detect indefinite widths where definite widths are required.
*
* Revision 1.28 2000/09/24 17:41:13 steve
* fix null pointer when elaborating undefined task.
*
* Revision 1.27 2000/08/26 01:31:29 steve
* Handle out of range part select expressions.
*
* Revision 1.26 2000/05/19 01:55:09 steve
* Catch part select of memories as an error.
*
* Revision 1.25 2000/05/07 18:20:07 steve
* Import MCD support from Stephen Tell, and add
* system function parameter support to the IVL core.
*
* Revision 1.24 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.23 2000/05/02 03:13:30 steve
* Move memories to the NetScope object.
*
* Revision 1.22 2000/05/02 00:58:11 steve
* Move signal tables to the NetScope class.
*
* Revision 1.21 2000/04/28 18:43:23 steve
* integer division in expressions properly get width.
*
* Revision 1.20 2000/03/29 04:06:28 steve
* Forgot to return elaborate result (Dan Nelsen)
*
* Revision 1.19 2000/03/20 16:57:22 steve
* select correct bit when reg has non-zero lsb.
*
* Revision 1.18 2000/03/12 18:22:11 steve
* Binary and unary operators in parameter expressions.
*
* Revision 1.17 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.16 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.15 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.14 2000/01/01 06:18:00 steve
* Handle synthesis of concatenation.
*
* Revision 1.13 1999/12/12 06:03:14 steve
* Allow memories without indices in expressions.
*
* Revision 1.12 1999/11/30 04:54:01 steve
* Match scope names as last resort.
*
-290
View File
@@ -1,290 +0,0 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: elab_lval.cc,v 1.4 2000/09/10 15:43:59 steve Exp $"
#endif
# include "PExpr.h"
# include "netlist.h"
/*
* These methods generate a NetAssign_ object for the l-value of the
* assignemnt. This is common code for the = and <= statements.
*
* What gets generated depends on the structure of the l-value. If the
* l-value is a simple name (i.e. foo <= <value>) the the NetAssign_
* is created the width of the foo reg and connected to all the
* bits.
*
* If there is a part select (i.e. foo[3:1] <= <value>) the NetAssign_
* is made only as wide as it needs to be (3 bits in this example) and
* connected to the correct bits of foo. A constant bit select is a
* special case of the part select.
*
* If the bit-select is non-constant (i.e. foo[<expr>] = <value>) the
* NetAssign_ is made wide enough to connect to all the bits of foo,
* then the mux expression is elaborated and attached to the
* NetAssign_ node as a b_mux value. The target must interpret the
* presense of a bmux value as taking a single bit and assigning it to
* the bit selected by the bmux expression.
*
* If the l-value expression is non-trivial, but can be fully
* evaluated at compile time (meaning any bit selects are constant)
* then elaboration will make a single NetAssign_ that connects to a
* synthetic reg that in turn connects to all the proper pins of the
* l-value.
*
* This last case can turn up in statements like: {a, b[1]} = c;
* rather then create a NetAssign_ for each item in the contatenation,
* elaboration makes a single NetAssign_ and connects it up properly.
*/
/*
* The default interpretation of an l-value to a procedural assignment
* is to try to make a net elaboration, and see if the result is
* suitable for assignment.
*/
NetAssign_* PExpr::elaborate_lval(Design*des, NetScope*scope) const
{
NetNet*ll = elaborate_net(des, scope->name(), 0, 0, 0, 0);
if (ll == 0) {
cerr << get_line() << ": Assignment l-value too complex."
<< endl;
return 0;
}
NetAssign_*lv = new NetAssign_(scope->local_symbol(), ll->pin_count());
for (unsigned idx = 0 ; idx < ll->pin_count() ; idx += 1)
connect(lv->pin(idx), ll->pin(idx));
des->add_node(lv);
return lv;
}
/*
* Concatenation expressions can appear as l-values. Handle them here.
*
* If adjacent l-values in the concatenation are not bit selects, then
* merge them into a single NetAssign_ object. This can happen is code
* like ``{ ...a, b, ...}''. As long as "a" and "b" do not have bit
* selects (or the bit selects are constant) we can merge the
* NetAssign_ objects.
*
* Be careful to get the bit order right. In the expression ``{a, b}''
* a is the MSB and b the LSB. Connect the LSB to the low pins of the
* NetAssign_ object.
*/
NetAssign_* PEConcat::elaborate_lval(Design*des, NetScope*scope) const
{
if (repeat_) {
cerr << get_line() << ": error: Repeat concatenations make "
"no sense in l-value expressions. I refuse." << endl;
des->errors += 1;
return 0;
}
NetAssign_*res = 0;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope);
assert(tmp);
/* If adjacent l-values in the concatenation are not bit
selects, then merge them into a single NetAssign_
object.
If we cannot merge, then just link the new one to the
previous one. */
if (res && (res->bmux() == 0) && (tmp->bmux() == 0)) {
unsigned wid1 = tmp->pin_count();
unsigned wid2 = res->pin_count() + tmp->pin_count();
NetAssign_*tmp2 = new NetAssign_(res->name(), wid2);
assert(tmp->more == 0);
tmp2->more = res->more;
res->more = 0;
for (unsigned idx = 0 ; idx < wid1 ; idx += 1)
connect(tmp2->pin(idx), tmp->pin(idx));
for (unsigned idx = 0 ; idx < res->pin_count() ; idx += 1)
connect(tmp2->pin(idx+wid1), res->pin(idx));
delete res;
delete tmp;
res = tmp2;
des->add_node(res);
} else {
NetAssign_*last = tmp;
while (last->more)
last = last->more;
last->more = res;
res = tmp;
}
}
return res;
}
/*
* Handle the ident as an l-value. This includes bit and part selects
* of that ident.
*/
NetAssign_* PEIdent::elaborate_lval(Design*des, NetScope*scope) const
{
/* Get the signal referenced by the identifier, and make sure
it is a register. (Wires are not allows in this context. */
NetNet*reg = des->find_signal(scope, name());
if (reg == 0) {
cerr << get_line() << ": error: Could not match signal ``" <<
name() << "'' in ``" << scope->name() << "''" << endl;
des->errors += 1;
return 0;
}
assert(reg);
if ((reg->type() != NetNet::REG) && (reg->type() != NetNet::INTEGER)) {
cerr << get_line() << ": error: " << name() <<
" is not a reg in " << scope->name() << "." << endl;
des->errors += 1;
return 0;
}
long msb, lsb;
NetExpr*mux;
if (msb_ && lsb_) {
/* This handles part selects. In this case, there are
two bit select expressions, and both must be
constant. Evaluate them and pass the results back to
the caller. */
verinum*vl = lsb_->eval_const(des, scope->name());
if (vl == 0) {
cerr << lsb_->get_line() << ": error: "
"Part select expressions must be constant: "
<< *lsb_;
des->errors += 1;
return 0;
}
verinum*vm = msb_->eval_const(des, scope->name());
if (vl == 0) {
cerr << msb_->get_line() << ": error: "
"Part select expressions must be constant: "
<< *msb_;
des->errors += 1;
return 0;
}
msb = vm->as_long();
lsb = vl->as_long();
mux = 0;
} else if (msb_) {
/* If there is only a single select expression, it is a
bit select. Evaluate the constant value and treat it
as a part select with a bit width of 1. If the
expression it not constant, then return the
expression as a mux. */
assert(lsb_ == 0);
verinum*v = msb_->eval_const(des, scope->name());
if (v == 0) {
NetExpr*m = msb_->elaborate_expr(des, scope);
assert(m);
msb = 0;
lsb = 0;
mux = m;
} else {
msb = v->as_long();
lsb = v->as_long();
mux = 0;
}
} else {
/* No select expressions, so presume a part select the
width of the register. */
assert(msb_ == 0);
assert(lsb_ == 0);
msb = reg->msb();
lsb = reg->lsb();
mux = 0;
}
NetAssign_*lv;
if (mux) {
/* If there is a non-constant bit select, make a
NetAssign_ the width of the target reg and attach a
bmux to select the target bit. */
unsigned wid = reg->pin_count();
lv = new NetAssign_(des->local_symbol(scope->name()), wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1)
connect(lv->pin(idx), reg->pin(idx));
lv->set_bmux(mux);
} else {
/* If the bit/part select is constant, then make the
NetAssign_ only as wide as it needs to be and connect
only to the selected bits of the reg. */
unsigned wid = (msb >= lsb)? (msb-lsb+1) : (lsb-msb+1);
assert(wid <= reg->pin_count());
lv = new NetAssign_(des->local_symbol(scope->name()), wid);
unsigned off = reg->sb_to_idx(lsb);
assert((off+wid) <= reg->pin_count());
for (unsigned idx = 0 ; idx < wid ; idx += 1)
connect(lv->pin(idx), reg->pin(idx+off));
}
des->add_node(lv);
return lv;
}
/*
* $Log: elab_lval.cc,v $
* Revision 1.4 2000/09/10 15:43:59 steve
* Some error checking.
*
* Revision 1.3 2000/09/10 03:59:59 steve
* Agressively merge NetAssign_ within concatenations.
*
* Revision 1.2 2000/09/10 02:18:16 steve
* elaborate complex l-values
*
* Revision 1.1 2000/09/09 15:21:26 steve
* move lval elaboration to PExpr virtual methods.
*
*/
+237 -1232
View File
File diff suppressed because it is too large Load Diff
-186
View File
@@ -1,186 +0,0 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: elab_pexpr.cc,v 1.5 2000/06/13 05:22:16 steve Exp $"
#endif
# include "PExpr.h"
NetExpr*PExpr::elaborate_pexpr(Design*des, NetScope*sc) const
{
cerr << get_line() << ": error: invalid parameter expression: "
<< *this << endl;
des->errors += 1;
return 0;
}
/*
* Binary operators have sub-expressions that must be elaborated as
* parameter expressions. If either of them fail, then give up. Once
* they are taken care of, make the base object just as in any other
* expression.
*/
NetExpr*PEBinary::elaborate_pexpr (Design*des, NetScope*scope) const
{
NetExpr*lp = left_->elaborate_pexpr(des, scope);
NetExpr*rp = right_->elaborate_pexpr(des, scope);
if ((lp == 0) || (rp == 0)) {
delete lp;
delete rp;
return 0;
}
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp);
return tmp;
}
/*
* Event though parameters are not generally sized, parameter
* expressions can include concatenation expressions. This requires
* that the subexpressions all have well-defined size (in spite of
* being in a parameter expression) in order to get a defined
* value. The sub-expressions themsilves must also be value parameter
* expressions.
*/
NetEConcat* PEConcat::elaborate_pexpr(Design*des, NetScope*scope) const
{
unsigned repeat = 1;
/* If there is a repeat expression, then evaluate the constant
value and set the repeat count.
XXXX Potential bug XXX In principle, the repeat expression
can have a parameter name in it. Since where are in the
working of parameters now, we will not be able to
accurately evaluate such expressions. So eventually, I will
need to be able to defer the evaluation of the expression. */
if (repeat_) {
verinum*vrep = repeat_->eval_const(des, scope->name());
if (vrep == 0) {
cerr << get_line() << ": error: "
"concatenation repeat expression cannot be evaluated."
<< endl;
des->errors += 1;
return 0;
}
repeat = vrep->as_ulong();
delete vrep;
}
/* Make the empty concat expression. */
NetEConcat*tmp = new NetEConcat(parms_.count(), repeat);
tmp->set_line(*this);
/* Elaborate all the operands and attach them to the concat
node. Use the elaborate_pexpr method instead of the
elaborate_expr method. */
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
assert(parms_[idx]);
NetExpr*ex = parms_[idx]->elaborate_pexpr(des, scope);
if (ex == 0) continue;
ex->set_line(*parms_[idx]);
tmp->set(idx, ex);
}
return tmp;
}
/*
* Parameter expressions may reference other parameters, but only in
* the current scope. Preserve the parameter reference in the
* parameter expression I'm generating, instead of evaluating it now,
* because the referenced parameter may yet be overridden.
*/
NetExpr*PEIdent::elaborate_pexpr(Design*des, NetScope*scope) const
{
const NetExpr*ex = scope->get_parameter(text_);
if (ex == 0) {
cerr << get_line() << ": error: identifier ``" << text_ <<
"'' is not a parameter in " << scope->name() << "." << endl;
des->errors += 1;
return 0;
}
NetExpr*res = new NetEParam(des, scope, text_);
assert(res);
return res;
}
/*
* Simple numbers can be elaborated by the elaborate_expr method.
*/
NetExpr*PENumber::elaborate_pexpr(Design*des, NetScope*sc) const
{
return elaborate_expr(des, sc);
}
NetEConst* PEString::elaborate_pexpr(Design*des, NetScope*scope) const
{
return elaborate_expr(des, scope);
}
NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
{
NetExpr*ip = expr_->elaborate_pexpr(des, scope);
if (ip == 0) return 0;
/* Should we evaluate expressions ahead of time,
* just like in PEBinary::elaborate_expr() ?
*/
NetEUnary*tmp;
switch (op_) {
default:
tmp = new NetEUnary(op_, ip);
tmp->set_line(*this);
break;
case '~':
tmp = new NetEUBits(op_, ip);
tmp->set_line(*this);
break;
}
return tmp;
}
/*
* $Log: elab_pexpr.cc,v $
* Revision 1.5 2000/06/13 05:22:16 steve
* Support concatenation in parameter expressions.
*
* Revision 1.4 2000/06/01 02:31:39 steve
* Parameters can be strings.
*
* Revision 1.3 2000/03/12 18:22:11 steve
* Binary and unary operators in parameter expressions.
*
* Revision 1.2 2000/03/12 04:35:22 steve
* Allow parameter identifiers in parameter expressions.
*
* Revision 1.1 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
*/
-450
View File
@@ -1,450 +0,0 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: elab_scope.cc,v 1.6 2000/07/30 18:25:43 steve Exp $"
#endif
/*
* Elaboration happens in two passes, generally. The first scans the
* pform to generate the NetScope tree and attach it to the Design
* object. The methods in this source file implement the elaboration
* of the scopes.
*/
# include "Module.h"
# include "PEvent.h"
# include "PExpr.h"
# include "PGate.h"
# include "PTask.h"
# include "PWire.h"
# include "Statement.h"
# include "netlist.h"
# include <typeinfo>
bool Module::elaborate_scope(Design*des, NetScope*scope) const
{
// Generate all the parameters that this instance of this
// module introduces to the design. This loop elaborates the
// parameters, but doesn't evaluate references to
// parameters. This scan practically locates all the
// parameters and puts them in the parameter table in the
// design.
// No expressions are evaluated, yet. For now, leave them in
// the pform and just place a NetEParam placeholder in the
// place of the elaborated expression.
typedef map<string,PExpr*>::const_iterator mparm_it_t;
// This loop scans the parameters in the module, and creates
// stub parameter entries in the scope for the parameter name.
for (mparm_it_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
scope->set_parameter((*cur).first, new NetEParam);
}
for (mparm_it_t cur = localparams.begin()
; cur != localparams.end() ; cur ++) {
scope->set_parameter((*cur).first, new NetEParam);
}
// Now scan the parameters again, this time elaborating them
// for use as parameter values. This is after the previous
// scan so that local parameter names can be used in the
// r-value expressions.
for (mparm_it_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
PExpr*ex = (*cur).second;
assert(ex);
NetExpr*val = ex->elaborate_pexpr(des, scope);
val = scope->set_parameter((*cur).first, val);
assert(val);
delete val;
}
for (mparm_it_t cur = localparams.begin()
; cur != localparams.end() ; cur ++) {
PExpr*ex = (*cur).second;
assert(ex);
NetExpr*val = ex->elaborate_pexpr(des, scope);
val = scope->set_parameter((*cur).first, val);
assert(val);
delete val;
}
// Run through the defparams for this module, elaborate the
// expressions in this context and save the result is a table
// for later final override.
// It is OK to elaborate the expressions of the defparam here
// because Verilog requires that the expressions only use
// local parameter names. It is *not* OK to do the override
// here becuase the parameter receiving the assignment may be
// in a scope not discovered by this pass.
for (mparm_it_t cur = defparms.begin()
; cur != defparms.end() ; cur ++ ) {
PExpr*ex = (*cur).second;
assert(ex);
NetExpr*val = ex->elaborate_pexpr(des, scope);
if (val == 0) continue;
scope->defparams[(*cur).first] = val;
}
// Tasks introduce new scopes, so scan the tasks in this
// module. Create a scope for the task and pass that to the
// elaborate_scope method of the PTask for detailed
// processing.
typedef map<string,PTask*>::const_iterator tasks_it_t;
for (tasks_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++ ) {
NetScope*task_scope = new NetScope(scope, (*cur).first,
NetScope::TASK);
(*cur).second->elaborate_scope(des, task_scope);
}
// Functions are very similar to tasks, at least from the
// perspective of scopes. So handle them exactly the same
// way.
typedef map<string,PFunction*>::const_iterator funcs_it_t;
for (funcs_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++ ) {
NetScope*func_scope = new NetScope(scope, (*cur).first,
NetScope::FUNC);
(*cur).second->elaborate_scope(des, func_scope);
}
// Gates include modules, which might introduce new scopes, so
// scan all of them to create those scopes.
typedef list<PGate*>::const_iterator gates_it_t;
for (gates_it_t cur = gates_.begin()
; cur != gates_.end() ; cur ++ ) {
(*cur) -> elaborate_scope(des, scope);
}
// initial and always blocks may contain begin-end and
// fork-join blocks that can introduce scopes. Therefore, I
// get to scan processes here.
typedef list<PProcess*>::const_iterator proc_it_t;
for (proc_it_t cur = behaviors_.begin()
; cur != behaviors_.end() ; cur ++ ) {
(*cur) -> statement() -> elaborate_scope(des, scope);
}
// Scan through all the named events in this scope. We do not
// need anything more then the current scope to do this
// elaboration, so do it now. This allows for normal
// elaboration to reference these events.
for (map<string,PEvent*>::const_iterator et = events.begin()
; et != events.end() ; et ++ ) {
(*et).second->elaborate_scope(des, scope);
}
return des->errors == 0;
}
void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
{
// Missing module instance names have already been rejected.
assert(get_name() != "");
string path = sc->name();
// Check for duplicate scopes. Simply look up the scope I'm
// about to create, and if I find it then somebody beat me to
// it.
if (NetScope*tmp = des->find_scope(path + "." + get_name())) {
cerr << get_line() << ": error: Instance/Scope name " <<
get_name() << " already used in this context." <<
endl;
des->errors += 1;
return;
}
// Create the new scope as a MODULE with my name.
NetScope*my_scope = new NetScope(sc, get_name(), NetScope::MODULE);
// Set time units and precision.
my_scope->time_unit(mod->time_unit);
my_scope->time_precision(mod->time_precision);
des->set_precision(mod->time_precision);
// This call actually arranges for the description of the
// module type to process this instance and handle parameters
// and sub-scopes that might occur. Parameters are also
// created in that scope, as they exist. (I'll override them
// later.)
mod->elaborate_scope(des, my_scope);
// Look for module parameter replacements. This map receives
// those replacements.
typedef map<string,PExpr*>::const_iterator mparm_it_t;
map<string,PExpr*> replace;
// Positional parameter overrides are matched to parameter
// names by using the param_names list of parameter
// names. This is an ordered list of names so the first name
// is parameter 0, the second parameter 1, and so on.
if (overrides_) {
assert(parms_ == 0);
list<string>::const_iterator cur = mod->param_names.begin();
for (unsigned idx = 0
; idx < overrides_->count()
; idx += 1, cur++) {
replace[*cur] = (*overrides_)[idx];
}
}
// Named parameter overrides carry a name with each override
// so the mapping into the replace list is much easier.
if (parms_) {
assert(overrides_ == 0);
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
replace[parms_[idx].name] = parms_[idx].parm;
}
// And here we scan the replacements we collected. Elaborate
// the expression in my context, then replace the sub-scope
// parameter value with the new expression.
for (mparm_it_t cur = replace.begin()
; cur != replace.end() ; cur ++ ) {
PExpr*tmp = (*cur).second;
NetExpr*val = tmp->elaborate_pexpr(des, sc);
val = my_scope->set_parameter((*cur).first, val);
assert(val);
delete val;
}
}
/*
* The isn't really able to create new scopes, but it does create the
* event name in the current scope, so can be done during the
* elaborate_scope scan.
*/
void PEvent::elaborate_scope(Design*des, NetScope*scope) const
{
NetEvent*ev = new NetEvent(name_);
ev->set_line(*this);
scope->add_event(ev);
}
void PFunction::elaborate_scope(Design*des, NetScope*scope) const
{
}
void PTask::elaborate_scope(Design*des, NetScope*scope) const
{
assert(scope->type() == NetScope::TASK);
}
/*
* The base statement does not have sub-statements and does not
* introduce any scope, so this is a no-op.
*/
void Statement::elaborate_scope(Design*, NetScope*) const
{
}
/*
* When I get a behavioral block, check to see if it has a name. If it
* does, then create a new scope for the statements within it,
* otherwise use the current scope. Use the selected scope to scan the
* statements that I contain.
*/
void PBlock::elaborate_scope(Design*des, NetScope*scope) const
{
NetScope*my_scope = scope;
if (name_ != "") {
my_scope = new NetScope(scope, name_, bl_type_==BL_PAR
? NetScope::FORK_JOIN
: NetScope::BEGIN_END);
}
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1)
list_[idx] -> elaborate_scope(des, my_scope);
}
/*
* The case statement itseof does not introduce scope, but contains
* other statements that may be named blocks. So scan the case items
* with the elaborate_scope method.
*/
void PCase::elaborate_scope(Design*des, NetScope*scope) const
{
assert(items_);
for (unsigned idx = 0 ; idx < (*items_).count() ; idx += 1) {
assert( (*items_)[idx] );
if (Statement*sp = (*items_)[idx]->stat)
sp -> elaborate_scope(des, scope);
}
}
/*
* The conditional statement (if-else) does not introduce scope, but
* the statements of the clauses may, so elaborate_scope the contained
* statements.
*/
void PCondit::elaborate_scope(Design*des, NetScope*scope) const
{
if (if_)
if_ -> elaborate_scope(des, scope);
if (else_)
else_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PDelayStatement::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PEventStatement::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PForever::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PForStatement::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PRepeat::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* Statements that contain a further statement but do not
* intrinsically add a scope need to elaborate_scope the contained
* statement.
*/
void PWhile::elaborate_scope(Design*des, NetScope*scope) const
{
if (statement_)
statement_ -> elaborate_scope(des, scope);
}
/*
* $Log: elab_scope.cc,v $
* Revision 1.6 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.5 2000/07/22 22:09:03 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.4 2000/04/09 17:44:30 steve
* Catch event declarations during scope elaborate.
*
* Revision 1.3 2000/03/12 17:09:41 steve
* Support localparam.
*
* Revision 1.2 2000/03/11 03:25:52 steve
* Locate scopes in statements.
*
* Revision 1.1 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
*/
-377
View File
@@ -1,377 +0,0 @@
/*
* Copyright (c) 2000 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) && !defined(macintosh)
#ident "$Id: elab_sig.cc,v 1.4 2000/09/07 22:37:48 steve Exp $"
#endif
# include "Module.h"
# include "PExpr.h"
# include "PGate.h"
# include "PTask.h"
# include "PWire.h"
# include "netlist.h"
# include "util.h"
bool Module::elaborate_sig(Design*des, NetScope*scope) const
{
bool flag = true;
// Get all the explicitly declared wires of the module and
// start the signals list with them.
const map<string,PWire*>&wl = get_wires();
for (map<string,PWire*>::const_iterator wt = wl.begin()
; wt != wl.end()
; wt ++ ) {
(*wt).second->elaborate_sig(des, scope);
}
// Get all the gates of the module and elaborate them by
// connecting them to the signals. The gate may be simple or
// complex. What we are looking for is gates that are modules
// that can create scopes and signals.
const list<PGate*>&gl = get_gates();
for (list<PGate*>::const_iterator gt = gl.begin()
; gt != gl.end()
; gt ++ ) {
flag &= (*gt)->elaborate_sig(des, scope);
}
typedef map<string,PFunction*>::const_iterator mfunc_it_t;
for (mfunc_it_t cur = funcs_.begin()
; cur != funcs_.end() ; cur ++) {
NetScope*fscope = scope->child((*cur).first);
if (scope == 0) {
cerr << (*cur).second->get_line() << ": internal error: "
<< "Child scope for function " << (*cur).first
<< " missing in " << scope->name() << "." << endl;
des->errors += 1;
continue;
}
(*cur).second->elaborate_sig(des, fscope);
}
// After all the wires are elaborated, we are free to
// elaborate the ports of the tasks defined within this
// module. Run through them now.
typedef map<string,PTask*>::const_iterator mtask_it_t;
for (mtask_it_t cur = tasks_.begin()
; cur != tasks_.end() ; cur ++) {
NetScope*tscope = scope->child((*cur).first);
assert(tscope);
(*cur).second->elaborate_sig(des, tscope);
}
return flag;
}
bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope,
Module*rmod) const
{
// Missing module instance names have already been rejected.
assert(get_name() != "");
if (msb_) {
cerr << get_line() << ": sorry: Module instantiation arrays "
"are not yet supported." << endl;
des->errors += 1;
return false;
}
// I know a priori that the elaborate_scope created the scope
// already, so just look it up as a child of the current scope.
NetScope*my_scope = scope->child(get_name());
assert(my_scope);
return rmod->elaborate_sig(des, my_scope);
}
/*
* A function definition exists within an elaborated module.
*/
void PFunction::elaborate_sig(Design*des, NetScope*scope) const
{
string fname = scope->basename();
assert(scope->type() == NetScope::FUNC);
svector<NetNet*>ports (ports_? ports_->count()+1 : 1);
/* Get the reg for the return value. I know the name of the
reg variable, and I know that it is in this scope, so look
it up directly. */
ports[0] = scope->find_signal(scope->basename());
if (ports[0] == 0) {
cerr << get_line() << ": internal error: function scope "
<< scope->name() << " is missing return reg "
<< fname << "." << endl;
scope->dump(cerr);
des->errors += 1;
return;
}
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
/* Parse the port name into the task name and the reg
name. We know by design that the port name is given
as two components: <func>.<port>. */
string pname = (*ports_)[idx]->name();
string ppath = parse_first_name(pname);
if (ppath != scope->basename()) {
cerr << get_line() << ": internal error: function "
<< "port " << (*ports_)[idx]->name()
<< " has wrong name for function "
<< scope->name() << "." << endl;
des->errors += 1;
}
NetNet*tmp = scope->find_signal(pname);
if (tmp == 0) {
cerr << get_line() << ": internal error: function "
<< scope->name() << " is missing port "
<< pname << "." << endl;
scope->dump(cerr);
des->errors += 1;
}
ports[idx+1] = tmp;
}
NetFuncDef*def = new NetFuncDef(scope, ports);
scope->set_func_def(def);
}
/*
* A task definition is a scope within an elaborated module. When we
* are elaborating signals, the scopes have already been created, as
* have the reg objects that are the parameters of this task. The
* elaborate_sig method of PTask is therefore left to connect the
* signals to the ports of the NetTaskDef definition. We know for
* certain that signals exist (They are in my scope!) so the port
* binding is sure to work.
*/
void PTask::elaborate_sig(Design*des, NetScope*scope) const
{
assert(scope->type() == NetScope::TASK);
svector<NetNet*>ports (ports_? ports_->count() : 0);
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
/* Parse the port name into the task name and the reg
name. We know by design that the port name is given
as two components: <task>.<port>. */
string pname = (*ports_)[idx]->name();
string ppath = parse_first_name(pname);
assert(pname != "");
/* check that the current scope really does have the
name of the first component of the task port name. Do
this by looking up the task scope in the parent of
the current scope. */
if (scope->parent()->child(ppath) != scope) {
cerr << "internal error: task scope " << ppath
<< " not the same as scope " << scope->name()
<< "?!" << endl;
return;
}
/* Find the signal for the port. We know by definition
that it is in the scope of the task, so look only in
the scope. */
NetNet*tmp = scope->find_signal(pname);
if (tmp == 0) {
cerr << get_line() << ": internal error: "
<< "Could not find port " << pname
<< " in scope " << scope->name() << endl;
scope->dump(cerr);
}
ports[idx] = tmp;
}
NetTaskDef*def = new NetTaskDef(scope->name(), ports);
scope->set_task_def(def);
}
bool PGate::elaborate_sig(Design*des, NetScope*scope) const
{
return true;
}
/*
* Elaborate a source wire. The "wire" is the declaration of wires,
* registers, ports and memories. The parser has already merged the
* multiple properties of a wire (i.e. "input wire") so come the
* elaboration this creates an object in the design that represent the
* defined item.
*/
void PWire::elaborate_sig(Design*des, NetScope*scope) const
{
/* The parser may produce hierarchical names for wires. I here
follow the scopes down to the base where I actually want to
elaborate the NetNet object. */
string basename = name_;
for (;;) {
string p = parse_first_name(basename);
if (basename == "") {
basename = p;
break;
}
scope = scope->child(p);
assert(scope);
}
const string path = scope->name();
NetNet::Type wtype = type_;
if (wtype == NetNet::IMPLICIT)
wtype = NetNet::WIRE;
if (wtype == NetNet::IMPLICIT_REG)
wtype = NetNet::REG;
unsigned wid = 1;
long lsb = 0, msb = 0;
if (msb_.count()) {
svector<long>mnum (msb_.count());
svector<long>lnum (msb_.count());
/* There may be multiple declarations of ranges, because
the symbol may have its range declared in i.e. input
and reg declarations. Calculate *all* the numbers
here. I will resolve the values later. */
for (unsigned idx = 0 ; idx < msb_.count() ; idx += 1) {
verinum*mval = msb_[idx]->eval_const(des,path);
if (mval == 0) {
cerr << msb_[idx]->get_line() << ": error: "
"Unable to evaluate constant expression ``" <<
*msb_[idx] << "''." << endl;
des->errors += 1;
return;
}
verinum*lval = lsb_[idx]->eval_const(des, path);
if (lval == 0) {
cerr << lsb_[idx]->get_line() << ": error: "
"Unable to evaluate constant expression ``" <<
*lsb_[idx] << "''." << endl;
des->errors += 1;
return;
}
mnum[idx] = mval->as_long();
lnum[idx] = lval->as_long();
delete mval;
delete lval;
}
/* Make sure all the values for msb and lsb match by
value. If not, report an error. */
for (unsigned idx = 1 ; idx < msb_.count() ; idx += 1) {
if ((mnum[idx] != mnum[0]) || (lnum[idx] != lnum[0])) {
cerr << get_line() << ": error: Inconsistent width, "
"[" << mnum[idx] << ":" << lnum[idx] << "]"
" vs. [" << mnum[0] << ":" << lnum[0] << "]"
" for signal ``" << basename << "''" << endl;
des->errors += 1;
return;
}
}
lsb = lnum[0];
msb = mnum[0];
if (mnum[0] > lnum[0])
wid = mnum[0] - lnum[0] + 1;
else
wid = lnum[0] - mnum[0] + 1;
}
if (lidx_ || ridx_) {
assert(lidx_ && ridx_);
// If the register has indices, then this is a
// memory. Create the memory object.
verinum*lval = lidx_->eval_const(des, path);
assert(lval);
verinum*rval = ridx_->eval_const(des, path);
assert(rval);
long lnum = lval->as_long();
long rnum = rval->as_long();
delete lval;
delete rval;
NetMemory*sig = new NetMemory(scope, path+"."+basename,
wid, lnum, rnum);
sig->set_attributes(attributes);
} else {
NetNet*sig = new NetNet(scope, path + "." +basename, wtype, msb, lsb);
sig->set_line(*this);
sig->port_type(port_type_);
sig->set_attributes(attributes);
verinum::V iv = verinum::Vz;
if (wtype == NetNet::REG)
iv = verinum::Vx;
}
}
/*
* $Log: elab_sig.cc,v $
* Revision 1.4 2000/09/07 22:37:48 steve
* ack, detect when lval fails.
*
* Revision 1.3 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.2 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.1 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
*/
+833 -1048
View File
File diff suppressed because it is too large Load Diff
+244 -263
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: emit.cc,v 1.54 2000/09/26 01:35:42 steve Exp $"
#if !defined(WINNT)
#ident "$Id: emit.cc,v 1.31 1999/11/28 23:42:02 steve Exp $"
#endif
/*
@@ -26,240 +26,190 @@
*/
# include "target.h"
# include "netlist.h"
# include <iostream>
# include <typeinfo>
# include <cassert>
bool NetNode::emit_node(struct target_t*tgt) const
void NetNode::emit_node(ostream&o, struct target_t*tgt) const
{
cerr << "EMIT: Gate type? " << typeid(*this).name() << endl;
return false;
}
bool NetLogic::emit_node(struct target_t*tgt) const
void NetLogic::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->logic(this);
return true;
tgt->logic(o, this);
}
bool NetUDP_COMB::emit_node(struct target_t*tgt) const
void NetUDP::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->udp_comb(this);
return true;
tgt->udp(o, this);
}
bool NetUDP::emit_node(struct target_t*tgt) const
void NetAddSub::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->udp(this);
return true;
tgt->lpm_add_sub(o, this);
}
bool NetAddSub::emit_node(struct target_t*tgt) const
void NetAssign::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_add_sub(this);
return true;
tgt->net_assign(o, this);
}
bool NetAssign_::emit_node(struct target_t*tgt) const
void NetAssignNB::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_assign(this);
return true;
tgt->net_assign_nb(o, this);
}
bool NetCaseCmp::emit_node(struct target_t*tgt) const
void NetCaseCmp::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_case_cmp(this);
return true;
tgt->net_case_cmp(o, this);
}
bool NetCAssign::emit_node(struct target_t*tgt) const
void NetCLShift::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_cassign(this);
return true;
tgt->lpm_clshift(o, this);
}
bool NetCLShift::emit_node(struct target_t*tgt) const
void NetCompare::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_clshift(this);
return true;
tgt->lpm_compare(o, this);
}
bool NetCompare::emit_node(struct target_t*tgt) const
void NetConst::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_compare(this);
return true;
tgt->net_const(o, this);
}
bool NetConst::emit_node(struct target_t*tgt) const
void NetFF::emit_node(ostream&o, struct target_t*tgt) const
{
return tgt->net_const(this);
tgt->lpm_ff(o, this);
}
bool NetDivide::emit_node(struct target_t*tgt) const
void NetMux::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_divide(this);
return true;
tgt->lpm_mux(o, this);
}
bool NetFF::emit_node(struct target_t*tgt) const
void NetRamDq::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_ff(this);
return true;
tgt->lpm_ram_dq(o, this);
}
bool NetForce::emit_node(struct target_t*tgt) const
void NetNEvent::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_force(this);
return true;
tgt->net_event(o, this);
}
bool NetModulo::emit_node(struct target_t*tgt) const
void NetBUFZ::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_modulo(this);
return true;
tgt->bufz(o, this);
}
bool NetMult::emit_node(struct target_t*tgt) const
bool NetProcTop::emit(ostream&o, struct target_t*tgt) const
{
tgt->lpm_mult(this);
return true;
return tgt->process(o, this);
}
bool NetMux::emit_node(struct target_t*tgt) const
{
tgt->lpm_mux(this);
return true;
}
bool NetRamDq::emit_node(struct target_t*tgt) const
{
tgt->lpm_ram_dq(this);
return true;
}
bool NetBUFZ::emit_node(struct target_t*tgt) const
{
return tgt->bufz(this);
}
bool NetProcTop::emit(struct target_t*tgt) const
{
return tgt->process(this);
}
bool NetProc::emit_proc(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;
}
bool NetAssign::emit_proc(struct target_t*tgt) const
bool NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign(this);
tgt->proc_assign(o, this);
return true;
}
bool NetAssignNB::emit_proc(struct target_t*tgt) const
bool NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign_nb(this);
tgt->proc_assign_nb(o, this);
return true;
}
bool NetAssignMem::emit_proc(struct target_t*tgt) const
bool NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign_mem(this);
tgt->proc_assign_mem(o, this);
return true;
}
bool NetAssignMemNB::emit_proc(struct target_t*tgt) const
bool NetAssignMemNB::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign_mem_nb(this);
tgt->proc_assign_mem_nb(o, this);
return true;
}
bool NetBlock::emit_proc(struct target_t*tgt) const
bool NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_block(this);
return tgt->proc_block(o, this);
}
bool NetCase::emit_proc(struct target_t*tgt) const
bool NetCase::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_case(this);
tgt->proc_case(o, this);
return true;
}
bool NetCAssign::emit_proc(struct target_t*tgt) const
bool NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_cassign(this);
}
bool NetCondit::emit_proc(struct target_t*tgt) const
{
tgt->proc_condit(this);
tgt->proc_condit(o, this);
return true;
}
bool NetDeassign::emit_proc(struct target_t*tgt) const
bool NetForever::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_deassign(this);
}
bool NetDisable::emit_proc(struct target_t*tgt) const
{
return tgt->proc_disable(this);
}
bool NetForce::emit_proc(struct target_t*tgt) const
{
return tgt->proc_force(this);
}
bool NetForever::emit_proc(struct target_t*tgt) const
{
tgt->proc_forever(this);
tgt->proc_forever(o, this);
return true;
}
bool NetPDelay::emit_proc(struct target_t*tgt) const
bool NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_delay(this);
}
bool NetPDelay::emit_proc_recurse(struct target_t*tgt) const
{
if (statement_) return statement_->emit_proc(tgt);
tgt->proc_delay(o, this);
return true;
}
bool NetRelease::emit_proc(struct target_t*tgt) const
void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
{
return tgt->proc_release(this);
if (statement_) statement_->emit_proc(o, tgt);
}
bool NetRepeat::emit_proc(struct target_t*tgt) const
bool NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_repeat(this);
tgt->proc_event(o, this);
return true;
}
bool NetSTask::emit_proc(struct target_t*tgt) const
void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
{
tgt->proc_stask(this);
if (statement_) statement_->emit_proc(o, tgt);
}
bool NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_repeat(o, this);
return true;
}
bool NetUTask::emit_proc(struct target_t*tgt) const
bool NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_utask(this);
tgt->proc_stask(o, this);
return true;
}
bool NetWhile::emit_proc(struct target_t*tgt) const
bool NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_while(this);
tgt->proc_utask(o, this);
return true;
}
void NetBlock::emit_recurse(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
{
if (last_ == 0)
return;
@@ -267,138 +217,101 @@ void NetBlock::emit_recurse(struct target_t*tgt) const
NetProc*cur = last_;
do {
cur = cur->next_;
cur->emit_proc(tgt);
cur->emit_proc(o, tgt);
} while (cur != last_);
}
void NetCondit::emit_recurse_if(struct target_t*tgt) const
void NetCondit::emit_recurse_if(ostream&o, struct target_t*tgt) const
{
if (if_)
if_->emit_proc(tgt);
if_->emit_proc(o, tgt);
}
void NetCondit::emit_recurse_else(struct target_t*tgt) const
void NetCondit::emit_recurse_else(ostream&o, struct target_t*tgt) const
{
if (else_)
else_->emit_proc(tgt);
else_->emit_proc(o, tgt);
}
bool NetEvProbe::emit_node(struct target_t*tgt) const
{
tgt->net_probe(this);
return true;
}
bool NetEvTrig::emit_proc(struct target_t*tgt) const
{
return tgt->proc_trigger(this);
}
bool NetEvWait::emit_proc(struct target_t*tgt) const
{
return tgt->proc_wait(this);
}
bool NetEvWait::emit_recurse(struct target_t*tgt) const
{
if (!statement_) return true;
return statement_->emit_proc(tgt);
}
void NetForever::emit_recurse(struct target_t*tgt) const
void NetForever::emit_recurse(ostream&o, struct target_t*tgt) const
{
if (statement_)
statement_->emit_proc(tgt);
statement_->emit_proc(o, tgt);
}
void NetRepeat::emit_recurse(struct target_t*tgt) const
void NetRepeat::emit_recurse(ostream&o, struct target_t*tgt) const
{
if (statement_)
statement_->emit_proc(tgt);
statement_->emit_proc(o, tgt);
}
void NetScope::emit_scope(struct target_t*tgt) const
void NetWhile::emit_proc_recurse(ostream&o, struct target_t*tgt) const
{
tgt->scope(this);
proc_->emit_proc(o, tgt);
}
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_)
tgt->event(cur);
bool Design::emit(ostream&o, struct target_t*tgt) const
{
bool rc = true;
tgt->start_design(o, this);
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_)
cur->emit_scope(tgt);
// enumerate the scopes
{ map<string,NetScope*>::const_iterator sc;
for (sc = scopes_.begin() ; sc != scopes_.end() ; sc++) {
tgt->scope(o, (*sc).second);
}
}
// emit signals
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
tgt->signal(cur);
tgt->signal(o, cur);
cur = cur->sig_next_;
} while (cur != signals_->sig_next_);
}
if (memories_) {
NetMemory*cur = memories_->snext_;
do {
tgt->memory(cur);
cur = cur->snext_;
} while (cur != memories_->snext_);
// emit memories
{
map<string,NetMemory*>::const_iterator mi;
for (mi = memories_.begin() ; mi != memories_.end() ; mi++) {
tgt->memory(o, (*mi).second);
}
}
}
void NetScope::emit_defs(struct target_t*tgt) const
{
switch (type_) {
case MODULE:
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_)
cur->emit_defs(tgt);
break;
case FUNC:
tgt->func_def(this->func_def());
break;
case TASK:
tgt->task_def(this->task_def());
break;
}
}
void NetWhile::emit_proc_recurse(struct target_t*tgt) const
{
proc_->emit_proc(tgt);
}
bool Design::emit(struct target_t*tgt) const
{
bool rc = true;
rc = rc && tgt->start_design(this);
if (rc == false)
return false;
// enumerate the scopes
root_scope_->emit_scope(tgt);
// emit nodes
if (nodes_) {
NetNode*cur = nodes_->node_next_;
do {
rc = rc && cur->emit_node(tgt);
cur->emit_node(o, tgt);
cur = cur->node_next_;
} while (cur != nodes_->node_next_);
}
// emit task and function definitions
root_scope_->emit_defs(tgt);
// 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;
for (ta = tasks_.begin() ; ta != tasks_.end() ; ta ++) {
tgt->task_def(o, (*ta).second);
}
}
// emit the processes
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
rc = rc && idx->emit(tgt);
rc = rc && idx->emit(o, tgt);
tgt->end_design(this);
tgt->end_design(o, this);
return rc;
}
@@ -417,6 +330,11 @@ void NetEConst::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_const(this);
}
void NetEIdent::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_ident(this);
}
void NetEMemory::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_memory(this);
@@ -433,11 +351,6 @@ void NetEScope::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_scope(this);
}
void NetESFunc::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_sfunc(this);
}
void NetEUFunc::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_ufunc(this);
@@ -463,12 +376,12 @@ void NetEUnary::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_unary(this);
}
bool emit(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)
return des->emit(tgt->meth);
return des->emit(o, tgt->meth);
}
}
@@ -476,67 +389,135 @@ bool emit(const Design*des, const char*type)
/*
* $Log: emit.cc,v $
* Revision 1.54 2000/09/26 01:35:42 steve
* Remove the obsolete NetEIdent class.
* Revision 1.31 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
*
* Revision 1.53 2000/09/17 21:26:15 steve
* Add support for modulus (Eric Aardoom)
* Revision 1.30 1999/11/27 19:07:57 steve
* Support the creation of scopes.
*
* Revision 1.52 2000/09/02 20:54:20 steve
* Rearrange NetAssign to make NetAssign_ separate.
* Revision 1.29 1999/11/21 00:13:08 steve
* Support memories in continuous assignments.
*
* Revision 1.51 2000/08/14 04:39:56 steve
* add th t-dll functions for net_const, net_bufz and processes.
* Revision 1.28 1999/11/14 23:43:45 steve
* Support combinatorial comparators.
*
* Revision 1.50 2000/08/09 03:43:45 steve
* Move all file manipulation out of target class.
* Revision 1.27 1999/11/14 20:24:28 steve
* Add support for the LPM_CLSHIFT device.
*
* Revision 1.49 2000/08/08 01:50:42 steve
* target methods need not take a file stream.
* Revision 1.26 1999/11/04 03:53:26 steve
* Patch to synthesize unary ~ and the ternary operator.
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
*
* Revision 1.48 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
* Add the LPM_MUX device, and integrate it with the
* ternary synthesis from Larry. Replace the lpm_mux
* generator in t-xnf.cc to use XNF EQU devices to
* put muxs into function units.
*
* Revision 1.47 2000/07/29 16:21:08 steve
* Report code generation errors through proc_delay.
* Rewrite elaborate_net for the PETernary class to
* also use the LPM_MUX device.
*
* Revision 1.46 2000/07/27 05:13:44 steve
* Support elaboration of disable statements.
* Revision 1.25 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.45 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
* Revision 1.24 1999/10/10 01:59:54 steve
* Structural case equals device.
*
* Revision 1.44 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
* Revision 1.23 1999/09/22 16:57:23 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.43 2000/05/02 03:13:31 steve
* Move memories to the NetScope object.
* Revision 1.22 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.42 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
* Revision 1.21 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.41 2000/04/23 03:45:24 steve
* Add support for the procedural release statement.
* Revision 1.20 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.40 2000/04/22 04:20:19 steve
* Add support for force assignment.
* Revision 1.19 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.39 2000/04/12 04:23:58 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
* Revision 1.18 1999/07/17 19:50:59 steve
* netlist support for ternary operator.
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
* Revision 1.17 1999/07/17 03:39:11 steve
* simplified process scan for targets.
*
* Revision 1.16 1999/07/07 04:20:57 steve
* Emit vvm for user defined tasks.
*
* Revision 1.15 1999/07/03 02:12:51 steve
* Elaborate user defined tasks.
*
* Revision 1.14 1999/06/19 21:06:16 steve
* Elaborate and supprort to vvm the forever
* and repeat statements.
*
* Revision 1.13 1999/06/09 03:00:06 steve
* Add support for procedural concatenation expression.
*
* Revision 1.12 1999/06/06 20:45:38 steve
* Add parse and elaboration of non-blocking assignments,
* Replace list<PCase::Item*> with an svector version,
* Add integer support.
*
* Revision 1.11 1999/05/12 04:03:19 steve
* emit NetAssignMem objects in vvm target.
*
* Revision 1.10 1999/05/07 01:21:18 steve
* Handle total lack of nodes and signals.
*
* Revision 1.9 1999/05/01 02:57:53 steve
* Handle much more complex event expressions.
*
* Revision 1.8 1999/04/25 00:44:10 steve
* Core handles subsignal expressions.
*
* Revision 1.7 1999/04/19 01:59:36 steve
* Add memories to the parse and elaboration phases.
*
* Revision 1.6 1999/02/08 02:49:56 steve
* Turn the NetESignal into a NetNode so
* that it can connect to the netlist.
* Implement the case statement.
* Convince t-vvm to output code for
* the case statement.
*
* Revision 1.5 1999/02/01 00:26:49 steve
* Carry some line info to the netlist,
* Dump line numbers for processes.
* Elaborate prints errors about port vector
* width mismatch
* Emit better handles null statements.
*
* Revision 1.4 1998/12/01 00:42:14 steve
* Elaborate UDP devices,
* Support UDP type attributes, and
* pass those attributes to nodes that
* are instantiated by elaboration,
* Put modules into a map instead of
* a simple list.
*
* Revision 1.3 1998/11/09 18:55:34 steve
* Add procedural while loops,
* Parse procedural for loops,
* Add procedural wait statements,
* Add constant nodes,
* Add XNOR logic gate,
* Make vvm output look a bit prettier.
*
* Revision 1.2 1998/11/07 17:05:05 steve
* Handle procedural conditional, and some
* of the conditional expressions.
*
* Elaborate signals and identifiers differently,
* allowing the netlist to hold signal information.
*
* Revision 1.1 1998/11/03 23:28:57 steve
* Introduce verilog to CVS.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*/
+4 -38
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: eval.cc,v 1.15 2000/09/07 22:38:13 steve Exp $"
#if !defined(WINNT)
#ident "$Id: eval.cc,v 1.12 1999/11/30 04:48:17 steve Exp $"
#endif
# include "PExpr.h"
@@ -96,9 +96,7 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
*/
verinum* PEIdent::eval_const(const Design*des, const string&path) const
{
const NetScope*scope = des->find_scope(path);
assert(scope);
const NetExpr*expr = des->find_parameter(scope, text_);
const NetExpr*expr = des->find_parameter(path, text_);
if (expr == 0)
return 0;
@@ -141,41 +139,9 @@ verinum* PETernary::eval_const(const Design*des, const string&path) const
}
}
verinum* PEUnary::eval_const(const Design*des, const string&path) const
{
verinum*val = expr_->eval_const(des, path);
if (val == 0)
return 0;
switch (op_) {
case '+':
return val;
case '-':
*val = v_not(*val) + verinum(verinum::V1, 1);
return val;
}
delete val;
return 0;
}
/*
* $Log: eval.cc,v $
* Revision 1.15 2000/09/07 22:38:13 steve
* Support unary + and - in constants.
*
* Revision 1.14 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.13 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.12 1999/11/30 04:48:17 steve
* Handle evaluation of ternary during elaboration.
*
+6 -184
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: eval_tree.cc,v 1.13 2000/09/29 04:42:56 steve Exp $"
#if !defined(WINNT)
#ident "$Id: eval_tree.cc,v 1.6 1999/10/22 23:57:53 steve Exp $"
#endif
# include "netlist.h"
@@ -115,91 +115,7 @@ NetEConst* NetEBComp::eval_leeq_()
return 0;
}
NetEConst* NetEBComp::eval_neeq_()
{
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();
verinum::V res = verinum::V0;
unsigned top = lv.len();
if (rv.len() < top)
top = rv.len();
for (unsigned idx = 0 ; idx < top ; idx += 1) {
switch (lv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
break;
default:
break;
}
switch (rv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
break;
default:
break;
}
if (res == verinum::Vx)
break;
if (rv.get(idx) != lv.get(idx))
res = verinum::V1;
}
if (res != verinum::Vx) {
for (unsigned idx = top ; idx < lv.len() ; idx += 1)
switch (lv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
break;
case verinum::V1:
if (res != verinum::Vx)
res = verinum::V1;
break;
default:
break;
}
for (unsigned idx = top ; idx < rv.len() ; idx += 1)
switch (rv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
break;
case verinum::V1:
if (res != verinum::Vx)
res = verinum::V1;
break;
default:
break;
}
}
return new NetEConst(verinum(res));
}
NetEConst* NetEBComp::eval_tree()
{
eval_sub_tree_();
@@ -211,41 +127,17 @@ NetEConst* NetEBComp::eval_tree()
case 'L':
return eval_leeq_();
case 'n':
return eval_neeq_();
default:
return 0;
}
}
NetEConst* NetEBDiv::eval_tree()
{
eval_sub_tree_();
return 0;
}
NetEConst* NetEBLogic::eval_tree()
{
eval_sub_tree_();
return 0;
}
NetEConst* NetEBMult::eval_tree()
{
eval_sub_tree_();
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
if (lc == 0) return 0;
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
if (rc == 0) return 0;
verinum lval = lc->value();
verinum rval = rc->value();
return new NetEConst(lval * rval);
}
/*
* Evaluate the shift operator if possible. For this to work, both
* operands must be constant.
@@ -343,8 +235,7 @@ NetExpr* NetEParam::eval_tree()
if (des_ == 0)
return 0;
assert(scope_);
const NetExpr*expr = scope_->get_parameter(name_);
const NetExpr*expr = des_->find_parameter(path_, name_);
assert(expr);
NetExpr*nexpr = expr->dup_expr();
@@ -365,81 +256,12 @@ NetExpr* NetEParam::eval_tree()
// The result can be saved as the value of the parameter for
// future reference, and return a copy to the caller.
scope_->set_parameter(name_, res);
des_->set_parameter(path_+"."+name_, res);
return res->dup_expr();
}
NetEConst* NetEUnary::eval_tree()
{
NetExpr*oper = expr_->eval_tree();
NetEConst*rval = dynamic_cast<NetEConst*>(oper);
if (rval == 0)
return 0;
verinum val = rval->value();
switch (op_) {
case '!': {
/* Evaluate the unary logical not by first scanning
the operand value for V1 and Vx bits. If we find
any V1 bits we know that the value is TRUE, so
the result of ! is V0. If there are no V1 bits
but there are some Vx/Vz bits, the result is
unknown. Otherwise, the result is V1. */
unsigned v1 = 0, vx = 0;
for (unsigned idx = 0 ; idx < val.len() ; idx += 1) {
switch (val.get(idx)) {
case verinum::V0:
break;
case verinum::V1:
v1 += 1;
break;
default:
vx += 1;
break;
}
}
verinum out(v1? verinum::V0 : (vx? verinum::Vx : verinum::V1));
return new NetEConst(out);
}
default:
delete rval;
return 0;
}
}
/*
* $Log: eval_tree.cc,v $
* Revision 1.13 2000/09/29 04:42:56 steve
* Cnstant evaluation of NE.
*
* Revision 1.12 2000/09/27 18:28:37 steve
* multiply in parameter expressions.
*
* Revision 1.11 2000/07/07 04:53:54 steve
* Add support for non-constant delays in delay statements,
* Support evaluating ! in constant expressions, and
* move some code from netlist.cc to net_proc.cc.
*
* Revision 1.10 2000/04/28 18:43:23 steve
* integer division in expressions properly get width.
*
* Revision 1.9 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.8 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.7 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.6 1999/10/22 23:57:53 steve
* do the <= in bits, not numbers.
*
-87
View File
@@ -1,87 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/*
* This source file demonstrates how to synthesize CLB flip-flops from
* Icarus Verilog, including giving the device an initial value.
*
* To compile this for XNF, try a command like this:
*
* iverilog -txnf -fpart=XC4010XLPQ160 -fncf=clbff.ncf -oclbff.xnf clbff.v
*
* That command causes an clbff.xnf and clbff.ncf file to be created.
* Next, make the clbff.ngd file with the command:
*
* xnf2ngd -l xilinxun -u clbff.xnf clbff.ngo
* ngdbuild clbff.ngo clbff.ngd
*
* Finally, map the file to fully render it in the target part. The
* par command is the step that actually optimizes the design and tries
* to meet timing constraints.
*
* map -o map.ncd clbff.ngd
* par -w map.ncd clbff.ncd
*
* At this point, you can use the FPGA Editor to edit the clbff.ncd
* file. Notice that the design uses two CLB flip-flops (possibly in
* the same CLB) with their outputs ANDed together. If you go into the
* block editor, you will see that the FF connected to main/Q<0> is
* configured so start up reset, and the FF connected to main/Q<1> is
* configured to start up set.
*/
module main;
wire clk, iclk;
wire i0, i1;
wire out;
wire [1:0] D = {i1, i0};
// This statement declares Q to be a 2 bit reg vector. The
// initial assignment will cause the synthesized device to take
// on an initial value specified here. Without the assignment,
// the initial value is unspecified. (Verilog simulates it as 2'bx.)
reg [1:0] Q = 2'b10;
// This simple logic gate get turned into a function unit.
// The par program will map this into a CLB F or G unit.
and (out, Q[0], Q[1]);
// This creates a global clock buffer. Notice how I attach an
// attribute to the named gate to force it to be mapped to the
// desired XNF device. This device will not be pulled into the
// IOB associated with iclk because of the attribute.
buf gbuf(clk, iclk);
$attribute(gbuf, "XNF-LCA", "GCLK:O,I");
// This is mapped to a DFF. Since Q and D are two bits wide, the
// code generator actually makes two DFF devices that share a
// clock input.
always @(posedge clk) Q <= D;
// These attribute commands assign pins to the listed wires.
// This can be done to wires and registers, as internally both
// are treated as named signals.
$attribute(out, "PAD", "o150");
$attribute(i0, "PAD", "i152");
$attribute(i1, "PAD", "i153");
$attribute(iclk,"PAD", "i154");
endmodule /* main */
-49
View File
@@ -1,49 +0,0 @@
/*
* Copyright (c) 1998 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
*/
/*
* Here we have the canonical "Hello, World" program written in Verilog.
* We simply print to the program output a simple message. This example
* demonstrates the process of compiling and executing a program with
* Icarus Verilog.
*
* Compile this program with the command:
*
* iverilog -ohello hello.vl
*
* After churning for a little while, the program will create the output
* file "hello" which is compiled, linked and ready to run. Run this
* program like so:
*
* ./hello
*
* and the program will print the message to its output. Easy! For
* more on how to make the iverilog command work, see the iverilog
* manual page.
*/
module main();
initial
begin
$display("Hello, World");
$finish ;
end
endmodule
-76
View File
@@ -1,76 +0,0 @@
/*
* 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
* 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
*/
/*
* IVL should generate an AND gate, and should make an OBUF and two
* IBUF objects, along with the PAD objects.
*
* To compile this for XNF, try a command like this:
*
* iverilog -txnf -fpart=XC4010XLPQ160 -ooutff.xnf -fncf=outff.ncf outff.v
*
* That command causes an outff.xnf and outff.ncf file to be created.
* Next, make the outff.ngd file with the command:
*
* xnf2ngd -l xilinxun -u outff.xnf outff.ngo
* ngdbuild outff.ngo outff.ngd
*
* Finally, map the file to fully render it in the target part. The
* par command is the step that actually optimizes the design and tries
* to meet timing constraints.
*
* map -o map.ncd outff.ngd
* par -w map.ncd outff.ncd
*
* At this point, you can use the FPGA Editor to edit the outff.ncd
* file to see that the AND gate is in a CLB and the IOB for pin 150
* has its flip-flop in use, and that gbuf is a global buffer.
*/
module main;
wire clk, iclk;
wire i0, i1;
wire out;
reg o0;
// This simple logic gate get turned into a function unit.
// The par program will map this into a CLB F or G unit.
and (out, i0, i1);
// This creates a global clock buffer. Notice how I attach an
// attribute to the named gate to force it to be mapped to the
// desired XNF device. This device will not be pulled into the
// IOB associated with iclk because of the attribute.
buf gbuf(clk, iclk);
$attribute(gbuf, "XNF-LCA", "GCLK:O,I");
// This is mapped to a DFF. Since o0 is connected to a PAD, it
// is turned into a OUTFF so that it get placed into an IOB.
always @(posedge clk) o0 = out;
// These attribute commands assign pins to the listed wires.
// This can be done to wires and registers, as internally both
// are treated as named signals.
$attribute(o0, "PAD", "o150");
$attribute(i0, "PAD", "i152");
$attribute(i1, "PAD", "i153");
$attribute(iclk,"PAD", "i154");
endmodule /* main */
-114
View File
@@ -1,114 +0,0 @@
/*
* 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
*/
/*
* This example program simulates a 16x1 ram, and is used as an
* example for using VCD output and waveform viewers.
*
* Like any other Verilog simulation, compile this program with the
* command:
*
* iverilog show_vcd.vl
*
* This will generate the show_vcd command in the current directory.
* When you run the command, you will see the output from all the
* calls to $display, but also there will be a dump file ``show_vcd.vcd''.
* The name of this file is set by the statement:
*
* $dumpfile("show_vcd.vcd");
*
* in the main module. The output file uses the standard VCD file format
* so can be viewed using off-the-shelf waveform viewers. The remaining
* steps describe how to use GTKWave to view the file. If you are using
* a different viewer, see the documentation for that tool.
*
* To view the output generated by running show_vcd, start the GTKWave
* viewer with the command:
*
* wave show_vcd.vcd
*
* The GTKWave program will display its main window, and show in a small
* status box (upper left corner) that it succeeded in loading the dump
* file. However, there are no waveforms displayed yet. Select signals to
* add to the waveform display using the menu selection:
*
* "Search --> Signal Search Tree"
*
* This will bring up a dialog box that shows in directory tree format
* the signals of the program. Select the signals you wish to view, and
* click one of the buttons on the bottom of the dialog box to display
* the selected signals in the waveform window. Click "Exit" on the box
* to get rid of it.
*
* The magic that makes all this work is contained in the $dumpfile and
* $dumpvars system tasks. The $dumpfile task tells the simulation where
* to write the VCD output. This task must be called once before the
* $dumpvars task is called.
*
* The $dumpvars task tells the simulation what variables to write to
* the VCD output. The first parameter is how far to descend while
* scanning a scope, and the remaining paramters are signals or scope
* names to include in the dump. If a scope name is given, all the
* signals within the scope are dumped. If a wire or register name is
* given, that signal is included.
*/
module ram16x1 (q, d, a, we, wclk);
output q;
input d;
input [3:0] a;
input we;
input wclk;
reg mem[15:0];
assign q = mem[a];
always @(posedge wclk) if (we) mem[a] = d;
endmodule /* ram16x1 */
module main;
wire q;
reg d;
reg [3:0] a;
reg we, wclk;
ram16x1 r1 (q, d, a, we, wclk);
initial begin
$dumpfile("show_vcd.vcd");
$dumpvars(1, main.r1);
wclk = 0;
we = 1;
for (a = 0 ; a < 4'hf ; a = a + 1) begin
d = a[0];
#1 wclk = 1;
#1 wclk = 0;
$display("r1[%x] == %b", a, q);
end
for (a = 0 ; a < 4'hf ; a = a + 1)
#1 if (q !== a[0]) begin
$display("FAILED -- mem[%h] !== %b", a, a[0]);
$finish;
end
$display("PASSED");
end
endmodule /* main */
-140
View File
@@ -1,140 +0,0 @@
/*
* 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
*
* $Id: sqrt.vl,v 1.2 2000/09/23 17:46:11 steve Exp $"
*/
/*
* This example shows that Icarus Verilog can run non-trivial
* programs, too. This uses a variety of Verilog language features
* to implement the module of a square-root device. The program
* uses IEEE1364-1995 language features and should work correctly
* on any Verilog compiler.
*
* Run the file with Icarus Verilog under UNIX using the command:
*
* % iverilog -osqrt sqrt.v
* % ./sqrt
*/
/*
* This module approximates the square root of an unsigned 32bit
* number. The algorithm works by doing a bit-wise binary search.
* Starting from the most significant bit, the accumulated value
* tries to put a 1 in the bit position. If that makes the square
* to big for the input, the bit is left zero, otherwise it is set
* in the result. This continues for each bit, decreasing in
* significance, until all the bits are calculated or all the
* remaining bits are zero.
*
* Since the result is an integer, this function really calculates
* value of the expression:
*
* x = floor(sqrt(y))
*
* where sqrt(y) is the exact square root of y and floor(N) is the
* largest integer <= N.
*
* For 32bit numbers, this will never run more then 16 iterations,
* which amounts to 16 clocks.
*/
module sqrt32(clk, rdy, reset, x, .y(acc));
input clk;
output rdy;
input reset;
input [31:0] x;
output [15:0] acc;
// acc holds the accumulated result, and acc2 is the accumulated
// square of the accumulated result.
reg [15:0] acc;
reg [31:0] acc2;
// Keep track of which bit I'm working on.
reg [4:0] bitl;
wire [15:0] bit = 1 << bitl;
wire [31:0] bit2 = 1 << (bitl << 1);
// The output is ready when the bitl counter underflows.
wire rdy = bitl[4];
// guess holds the potential next values for acc, and guess2 holds
// the square of that guess. The guess2 calculation is a little bit
// subtle. The idea is that:
//
// guess2 = (acc + bit) * (acc + bit)
// = (acc * acc) + 2*acc*bit + bit*bit
// = acc2 + 2*acc*bit + bit2
// = acc2 + 2 * (acc<<bitl) + bit
//
// This works out using shifts because bit and bit2 are known to
// have only a single bit in them.
wire [15:0] guess = acc | bit;
wire [31:0] guess2 = acc2 + bit2 + ((acc << bitl) << 1);
task clear;
begin
acc = 0;
acc2 = 0;
bitl = 15;
end
endtask
initial clear;
always @(reset or posedge clk)
if (reset)
clear;
else begin
if (guess2 <= x) begin
acc <= guess;
acc2 <= guess2;
end
bitl <= bitl - 1;
end
endmodule
module main;
reg clk, reset;
reg [31:0] value;
wire [15:0] result;
wire rdy;
sqrt32 root(.clk(clk), .rdy(rdy), .reset(reset), .x(value), .y(result));
always #5 clk = ~clk;
always @(posedge rdy) begin
$display("sqrt(%d) --> %d", value, result);
$finish;
end
initial begin
clk = 0;
reset = 1;
$monitor($time,,"%m = %b", root.acc, root.acc);
#100 value = 63;
reset = 0;
end
endmodule /* main */
-103
View File
@@ -1,103 +0,0 @@
/*
* 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
*/
/*
* This example demonstrates Icarus Verilog's ability to synthesize
* efficient adders for Xilinx 4000 series FPGAs. The synthesis and
* code generation makes an adder and translates that into XOR gates
* and fast carry chain hardware.
*
* To compile this for XNF, try a command like this:
*
* iverilog -txnf -fpart=XC4010XLPQ160 -fncf=xnf_add.ncf -oxnf_add.xnf xnf_add.v
*
* That command causes an xnf_add.xnf and xnf_add.ncf file to be created.
* Next, Use Xilinx Alliance or Foundation tools to make the xnf_add.ngd
* file with the command:
*
* xnf2ngd -l xilinxun -u xnf_add.xnf xnf_add.ngo
* ngdbuild xnf_add.ngo xnf_add.ngd
*
* Finally, map the file to fully render it in the target part. The
* par command is the step that actually optimizes the design and tries
* to meet timing constraints.
*
* map -o map.ncd xnf_add.ngd
* par -w map.ncd xnf_add.ncd
*
* At this point, you can use the Xilinx FPGA Editor to edit the xnf_add.ncd
* file and see the carry chains made up to support the adder.
*/
module main;
wire [3:0] a, b;
wire [3:0] out;
wire carry;
wire a0, a1, a2, a3, b0, b1, b2, b3;
wire out0, out1, out2, out3;
// This creates the actual adder. Note that we also create a link
// to the carry output. The principle adder is 4 bits wide, so two
// IOBs are used to to the actual addition. PAR will place them in
// order along carry lines. An extra carry cell from below a[0] is
// used in FORCE-0 mode to load the bottom carry node.
//
// The carry signal from the top CY device is used to drive the
// main.carry wire shown here. It is managed in this case by using
// an ADD-FG-CI CY device for the top pair and using the CLB above
// the carry chain, with its CY in EXAMINE-CI mode, to put the carry
// out through its G function unit.
assign {carry, out} = a + b;
// These attribute commands assign pins to the listed wires.
// This can be done to wires and registers, as internally both
// are treated as named signals. It doesn't work (yet) on vectors,
// though, so break out the vectors with scaler assignments.
assign a[0] = a0;
assign a[1] = a1;
assign a[2] = a2;
assign a[3] = a3;
$attribute(a0, "PAD", "i150");
$attribute(a1, "PAD", "i152");
$attribute(a2, "PAD", "i153");
$attribute(a3, "PAD", "i154");
assign b[0] = b0;
assign b[1] = b1;
assign b[2] = b2;
assign b[3] = b3;
$attribute(b0, "PAD", "i155");
$attribute(b1, "PAD", "i156");
$attribute(b2, "PAD", "i157");
$attribute(b3, "PAD", "i158");
assign out0 = out[0];
assign out1 = out[1];
assign out2 = out[2];
assign out3 = out[3];
$attribute(out0, "PAD", "o71");
$attribute(out1, "PAD", "o72");
$attribute(out2, "PAD", "o73");
$attribute(out3, "PAD", "o74");
$attribute(carry, "PAD", "o75");
endmodule /* main */
+27 -186
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: expr_synth.cc,v 1.15 2000/10/07 19:45:43 steve Exp $"
#if !defined(WINNT)
#ident "$Id: expr_synth.cc,v 1.6 1999/11/28 23:42:02 steve Exp $"
#endif
# include "netlist.h"
@@ -45,7 +45,7 @@ NetNet* NetEBAdd::synthesize(Design*des)
assert(lsig->pin_count() == rsig->pin_count());
unsigned width=lsig->pin_count();
NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, width);
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
string oname = des->local_symbol(path);
NetAddSub *adder = new NetAddSub(oname, width);
@@ -55,6 +55,7 @@ NetNet* NetEBAdd::synthesize(Design*des)
connect(osig->pin(idx), adder->pin_Result(idx));
}
des->add_node(adder);
des->add_signal(osig);
switch (op()) {
case '+':
@@ -76,17 +77,12 @@ NetNet* NetEBAdd::synthesize(Design*des)
*/
NetNet* NetEBBits::synthesize(Design*des)
{
string path = des->local_symbol("SYNTH");
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
NetScope*scope = lsig->scope();
assert(scope);
string path = des->local_symbol(scope->name());
assert(lsig->pin_count() == rsig->pin_count());
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT,
lsig->pin_count());
osig->local_flag(true);
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, lsig->pin_count());
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
string oname = des->local_symbol(path);
@@ -94,19 +90,19 @@ NetNet* NetEBBits::synthesize(Design*des)
switch (op()) {
case '&':
gate = new NetLogic(scope, oname, 3, NetLogic::AND);
gate = new NetLogic(oname, 3, NetLogic::AND);
break;
case '|':
gate = new NetLogic(scope, oname, 3, NetLogic::OR);
gate = new NetLogic(oname, 3, NetLogic::OR);
break;
case '^':
gate = new NetLogic(scope, oname, 3, NetLogic::XOR);
gate = new NetLogic(oname, 3, NetLogic::XOR);
break;
case 'O':
gate = new NetLogic(scope, oname, 3, NetLogic::NOR);
gate = new NetLogic(oname, 3, NetLogic::NOR);
break;
case 'X':
gate = new NetLogic(scope, oname, 3, NetLogic::XNOR);
gate = new NetLogic(oname, 3, NetLogic::XNOR);
break;
default:
assert(0);
@@ -119,142 +115,23 @@ NetNet* NetEBBits::synthesize(Design*des)
des->add_node(gate);
}
return osig;
}
NetNet* NetEBComp::synthesize(Design*des)
{
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
NetScope*scope = lsig->scope();
assert(scope);
string path = des->local_symbol(scope->name());
unsigned width = lsig->pin_count();
if (rsig->pin_count() > lsig->pin_count())
width = rsig->pin_count();
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, 1);
osig->local_flag(true);
/* Handle the special case of a single bit equality
operation. Make an XNOR gate instead of a comparator. */
if ((width == 1) && ((op_ == 'e') || (op_ == 'E'))) {
NetLogic*gate = new NetLogic(scope, des->local_symbol(path),
3, NetLogic::XNOR);
connect(gate->pin(0), osig->pin(0));
connect(gate->pin(1), lsig->pin(0));
connect(gate->pin(2), rsig->pin(0));
des->add_node(gate);
return osig;
}
/* Handle the special case of a single bit inequality
operation. This is similar to single bit equality, but uses
an XOR instead of an XNOR gate. */
if ((width == 1) && ((op_ == 'n') || (op_ == 'N'))) {
NetLogic*gate = new NetLogic(scope, des->local_symbol(path),
3, NetLogic::XOR);
connect(gate->pin(0), osig->pin(0));
connect(gate->pin(1), lsig->pin(0));
connect(gate->pin(2), rsig->pin(0));
des->add_node(gate);
return osig;
}
NetCompare*dev = new NetCompare(des->local_symbol(path), width);
des->add_node(dev);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
connect(dev->pin_DataA(idx), lsig->pin(idx));
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
connect(dev->pin_DataB(idx), rsig->pin(idx));
switch (op_) {
case '<':
connect(dev->pin_ALB(), osig->pin(0));
break;
case '>':
connect(dev->pin_AGB(), osig->pin(0));
break;
case 'e': // ==
case 'E': // === ?
connect(dev->pin_AEB(), osig->pin(0));
break;
case 'G': // >=
connect(dev->pin_AGEB(), osig->pin(0));
break;
case 'L': // <=
connect(dev->pin_ALEB(), osig->pin(0));
break;
case 'n': // !=
case 'N': // !==
connect(dev->pin_ANEB(), osig->pin(0));
break;
default:
cerr << get_line() << ": internal error: cannot synthesize "
"comparison: " << *this << endl;
des->errors += 1;
return 0;
}
return osig;
}
NetNet* NetEBDiv::synthesize(Design*des)
{
cerr << get_line() << ": internal error: cannot synthesize division: "
<< *this << endl;
des->errors += 1;
return 0;
}
NetNet* NetEConcat::synthesize(Design*des)
{
NetScope*scope = des->find_root_scope();
assert(scope);
assert(repeat_ == 1);
string path = des->local_symbol("SYNTH");
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width());
osig->local_flag(true);
unsigned obit = 0;
for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) {
NetNet*tmp = parms_[idx-1]->synthesize(des);
for (unsigned bit = 0 ; bit < tmp->pin_count() ; bit += 1) {
connect(osig->pin(obit), tmp->pin(bit));
obit += 1;
}
if (tmp->local_flag())
delete tmp;
}
des->add_signal(osig);
return osig;
}
NetNet* NetEConst::synthesize(Design*des)
{
NetScope*scope = des->find_root_scope();
assert(scope);
string path = des->local_symbol("SYNTH");
unsigned width=expr_width();
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width);
osig->local_flag(true);
NetConst*con = new NetConst(des->local_symbol(path), value());
for (unsigned idx = 0 ; idx < width; idx += 1)
connect(osig->pin(idx), con->pin(idx));
des->add_node(con);
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
for (unsigned idx = 0 ; idx < width; idx += 1) {
string oname = des->local_symbol(path);
NetConst *c = new NetConst(oname, value().get(idx));
connect(osig->pin(idx), c->pin(0));
des->add_node(c);
}
des->add_signal(osig);
return osig;
}
@@ -264,15 +141,10 @@ NetNet* NetEConst::synthesize(Design*des)
*/
NetNet* NetEUBits::synthesize(Design*des)
{
string path = des->local_symbol("SYNTH");
NetNet*isig = expr_->synthesize(des);
NetScope*scope = isig->scope();
assert(scope);
string path = des->local_symbol(scope->name());
NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT,
isig->pin_count());
osig->local_flag(true);
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, isig->pin_count());
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1) {
string oname = des->local_symbol(path);
@@ -280,7 +152,7 @@ NetNet* NetEUBits::synthesize(Design*des)
switch (op()) {
case '~':
gate = new NetLogic(scope, oname, 2, NetLogic::NOT);
gate = new NetLogic(oname, 2, NetLogic::NOT);
break;
default:
assert(0);
@@ -291,7 +163,7 @@ NetNet* NetEUBits::synthesize(Design*des)
des->add_node(gate);
}
des->add_signal(osig);
return osig;
}
@@ -306,8 +178,7 @@ NetNet* NetETernary::synthesize(Design *des)
assert(csig->pin_count() == 1);
assert(tsig->pin_count() == fsig->pin_count());
unsigned width=tsig->pin_count();
NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width);
osig->local_flag(true);
NetNet*osig = new NetNet(0, path, NetNet::IMPLICIT, width);
string oname = des->local_symbol(path);
NetMux *mux = new NetMux(oname, width, 2, 1);
@@ -318,7 +189,7 @@ NetNet* NetETernary::synthesize(Design *des)
}
des->add_node(mux);
connect(csig->pin(0), mux->pin_Sel(0));
des->add_signal(osig);
return osig;
}
@@ -329,36 +200,6 @@ NetNet* NetESignal::synthesize(Design*des)
/*
* $Log: expr_synth.cc,v $
* Revision 1.15 2000/10/07 19:45:43 steve
* Put logic devices into scopes.
*
* Revision 1.14 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.13 2000/04/28 18:43:23 steve
* integer division in expressions properly get width.
*
* Revision 1.12 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
* Revision 1.11 2000/04/16 23:32:18 steve
* Synthesis of comparator in expressions.
*
* Connect the NetEvent and related classes
* together better.
*
* Revision 1.10 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.9 2000/01/01 06:18:00 steve
* Handle synthesis of concatenation.
*
* Revision 1.8 1999/12/17 06:18:15 steve
* Rewrite the cprop functor to use the functor_t interface.
*
* Revision 1.7 1999/12/17 03:38:46 steve
* NetConst can now hold wide constants.
*
* Revision 1.6 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
+12 -222
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: functor.cc,v 1.22 2000/09/17 21:26:15 steve Exp $"
#if !defined(WINNT)
#ident "$Id: functor.cc,v 1.5 1999/12/01 06:06:16 steve Exp $"
#endif
# include "functor.h"
@@ -27,10 +27,6 @@ functor_t::~functor_t()
{
}
void functor_t::event(class Design*, class NetEvent*)
{
}
void functor_t::signal(class Design*, class NetNet*)
{
}
@@ -39,70 +35,21 @@ void functor_t::process(class Design*, class NetProcTop*)
{
}
void functor_t::lpm_add_sub(class Design*, class NetAddSub*)
{
}
void functor_t::lpm_compare(class Design*, class NetCompare*)
{
}
void functor_t::lpm_const(class Design*, class NetConst*)
{
}
void functor_t::lpm_divide(class Design*, class NetDivide*)
{
}
void functor_t::lpm_modulo(class Design*, class NetModulo*)
{
}
void functor_t::lpm_ff(class Design*, class NetFF*)
{
}
void functor_t::lpm_logic(class Design*, class NetLogic*)
void Design::functor(functor_t*fun)
{
}
void functor_t::lpm_mult(class Design*, class NetMult*)
{
}
void functor_t::lpm_mux(class Design*, class NetMux*)
{
}
void NetScope::run_functor(Design*des, functor_t*fun)
{
for (NetScope*cur = sub_ ; cur ; cur = cur->sib_) {
cur->run_functor(des, fun);
}
for (NetEvent*cur = events_ ; cur ; /* */) {
NetEvent*tmp = cur;
cur = cur->snext_;
fun->event(des, tmp);
}
// apply to signals
if (signals_) {
NetNet*cur = signals_->sig_next_;
do {
NetNet*tmp = cur->sig_next_;
fun->signal(des, cur);
fun->signal(this, cur);
cur = tmp;
} while (cur != signals_->sig_next_);
}
}
void Design::functor(functor_t*fun)
{
// Scan the scopes
root_scope_->run_functor(this, fun);
// apply to processes
procs_idx_ = procs_;
@@ -114,30 +61,12 @@ void Design::functor(functor_t*fun)
// apply to nodes
if (nodes_) {
/* Scan the circular list of nodes, starting with the
front of the list. (nodes_ points to the *end* of the
list.) The bar is the end point. At the end of the
do-while loop, I know that the bar has been
processed or (if bar == 0) no undeleted node has been
processed. */
NetNode*cur = nodes_->node_next_;
NetNode*bar = 0;
do {
NetNode*tmp = cur->node_next_;
cur->functor_node(this, fun);
/* Detect the case that cur has been deleted by
noticing if tmp->node_prev_ no longer points to
cur. If that's the case, clear the bar. */
if (tmp->node_prev_ != cur) {
if (cur == bar)
bar = 0;
} else if (bar == 0) {
bar = cur;
}
cur = tmp;
} while (nodes_ && (cur != bar));
} while (cur != nodes_->node_next_);
}
}
@@ -146,51 +75,11 @@ void NetNode::functor_node(Design*, functor_t*)
{
}
void NetAddSub::functor_node(Design*des, functor_t*fun)
{
fun->lpm_add_sub(des, this);
}
void NetCompare::functor_node(Design*des, functor_t*fun)
{
fun->lpm_compare(des, this);
}
void NetConst::functor_node(Design*des, functor_t*fun)
{
fun->lpm_const(des, this);
}
void NetDivide::functor_node(Design*des, functor_t*fun)
{
fun->lpm_divide(des, this);
}
void NetFF::functor_node(Design*des, functor_t*fun)
{
fun->lpm_ff(des, this);
}
void NetLogic::functor_node(Design*des, functor_t*fun)
{
fun->lpm_logic(des, this);
}
void NetModulo::functor_node(Design*des, functor_t*fun)
{
fun->lpm_modulo(des, this);
}
void NetMult::functor_node(Design*des, functor_t*fun)
{
fun->lpm_mult(des, this);
}
void NetMux::functor_node(Design*des, functor_t*fun)
{
fun->lpm_mux(des, this);
}
proc_match_t::~proc_match_t()
{
}
@@ -210,48 +99,6 @@ int NetAssign::match_proc(proc_match_t*that)
return that->assign(this);
}
int proc_match_t::assign_nb(NetAssignNB*)
{
return 0;
}
int NetAssignNB::match_proc(proc_match_t*that)
{
return that->assign_nb(this);
}
int proc_match_t::assign_mem(NetAssignMem*)
{
return 0;
}
int NetAssignMem::match_proc(proc_match_t*that)
{
return that->assign_mem(this);
}
int proc_match_t::assign_mem_nb(NetAssignMemNB*)
{
return 0;
}
int NetAssignMemNB::match_proc(proc_match_t*that)
{
return that->assign_mem_nb(this);
}
int proc_match_t::block(NetBlock*)
{
cerr << "default (failing) match for block" << endl;
return 0;
}
int NetBlock::match_proc(proc_match_t*that)
{
cerr << "NetBlock::match_proc" << endl;
return that->block(this);
}
int proc_match_t::condit(NetCondit*)
{
return 0;
@@ -262,75 +109,18 @@ int NetCondit::match_proc(proc_match_t*that)
return that->condit(this);
}
int NetEvWait::match_proc(proc_match_t*that)
{
return that->event_wait(this);
}
int proc_match_t::event_wait(NetEvWait*)
int proc_match_t::pevent(NetPEvent*)
{
return 0;
}
int NetPEvent::match_proc(proc_match_t*that)
{
return that->pevent(this);
}
/*
* $Log: functor.cc,v $
* Revision 1.22 2000/09/17 21:26:15 steve
* Add support for modulus (Eric Aardoom)
*
* Revision 1.21 2000/08/01 02:48:41 steve
* Support <= in synthesis of DFF and ram devices.
*
* Revision 1.20 2000/07/16 04:56:07 steve
* Handle some edge cases during node scans.
*
* Revision 1.19 2000/07/15 05:13:43 steve
* Detect muxing Vz as a bufufN.
*
* Revision 1.18 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.17 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
* Revision 1.16 2000/04/18 04:50:19 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.15 2000/04/16 23:32:18 steve
* Synthesis of comparator in expressions.
*
* Connect the NetEvent and related classes
* together better.
*
* Revision 1.14 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*
* Revision 1.13 2000/04/01 21:40:22 steve
* Add support for integer division.
*
* Revision 1.12 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.11 2000/02/13 04:35:43 steve
* Include some block matching from Larry.
*
* Revision 1.10 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.9 2000/01/02 17:57:20 steve
* Handle nodes running out during node scan.
*
* Revision 1.8 1999/12/30 04:19:12 steve
* Propogate constant 0 in low bits of adders.
*
* Revision 1.7 1999/12/17 06:18:16 steve
* Rewrite the cprop functor to use the functor_t interface.
*
* Revision 1.6 1999/12/05 02:24:08 steve
* Synthesize LPM_RAM_DQ for writes into memories.
*
* Revision 1.5 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
+14 -81
View File
@@ -1,7 +1,7 @@
#ifndef __functor_H
#define __functor_H
/*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -18,21 +18,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: functor.h,v 1.17 2000/09/17 21:26:15 steve Exp $"
#if !defined(WINNT)
#ident "$Id: functor.h,v 1.3 1999/12/01 06:06:16 steve Exp $"
#endif
/*
* The functor is an object that can be applied to a design to
* transform it. This is different from the target_t, which can only
* scan the design but not transform it in any way.
*
* When a functor it scanning a process, signal or node, the functor
* is free to manipulate the list by deleting items, including the
* node being scanned. The Design class scanner knows how to handle
* the situation. However, if objects are added to the netlist, there
* is no guarantee that object will be scanned unless the functor is
* rerun.
*/
class Design;
@@ -42,98 +35,38 @@ class NetProcTop;
struct functor_t {
virtual ~functor_t();
/* Events are scanned here. */
virtual void event(class Design*des, class NetEvent*);
/* This is called once for each signal in the design. */
/* Signals are scanned first. This is called once for each
signal in the design. */
virtual void signal(class Design*des, class NetNet*);
/* This method is called for each process in the design. */
virtual void process(class Design*des, class NetProcTop*);
/* This method is called for each structural adder. */
virtual void lpm_add_sub(class Design*des, class NetAddSub*);
/* This method is called for each structural comparator. */
virtual void lpm_compare(class Design*des, class NetCompare*);
/* This method is called for each structural constant. */
virtual void lpm_const(class Design*des, class NetConst*);
/* This method is called for each structural constant. */
virtual void lpm_divide(class Design*des, class NetDivide*);
/* This method is called for each structural constant. */
virtual void lpm_modulo(class Design*des, class NetModulo*);
/* This method is called for each FF in the design. */
virtual void lpm_ff(class Design*des, class NetFF*);
/* Handle LPM combinational logic devices. */
virtual void lpm_logic(class Design*des, class NetLogic*);
/* This method is called for each multiplier. */
virtual void lpm_mult(class Design*des, class NetMult*);
/* This method is called for each MUX. */
virtual void lpm_mux(class Design*des, class NetMux*);
};
struct proc_match_t {
virtual ~proc_match_t();
virtual int assign(class NetAssign*);
virtual int assign_mem(class NetAssignMem*);
virtual int assign_nb(class NetAssignNB*);
virtual int assign_mem_nb(class NetAssignMemNB*);
virtual int condit(class NetCondit*);
virtual int event_wait(class NetEvWait*);
virtual int block(class NetBlock*);
virtual int pevent(class NetPEvent*);
};
/*
* $Log: functor.h,v $
* Revision 1.17 2000/09/17 21:26:15 steve
* Add support for modulus (Eric Aardoom)
* Revision 1.3 1999/12/01 06:06:16 steve
* Redo synth to use match_proc_t scanner.
*
* Revision 1.16 2000/08/01 02:48:42 steve
* Support <= in synthesis of DFF and ram devices.
* Revision 1.2 1999/11/01 02:07:40 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.15 2000/07/16 04:56:07 steve
* Handle some edge cases during node scans.
* Revision 1.1 1999/07/17 22:01:13 steve
* Add the functor interface for functor transforms.
*
* Revision 1.14 2000/07/15 05:13:44 steve
* Detect muxing Vz as a bufufN.
*
* Revision 1.13 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
* Revision 1.12 2000/04/18 04:50:19 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.11 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*
* Revision 1.10 2000/04/01 21:40:22 steve
* Add support for integer division.
*
* Revision 1.9 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.8 2000/02/13 04:35:43 steve
* Include some block matching from Larry.
*
* Revision 1.7 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.6 1999/12/30 04:19:12 steve
* Propogate constant 0 in low bits of adders.
*
* Revision 1.5 1999/12/17 06:18:16 steve
* Rewrite the cprop functor to use the functor_t interface.
*/
#endif
-107
View File
@@ -1,107 +0,0 @@
Icarus Verilog vs. IEEE1364
Copyright 2000 Stephen Williams
The IEEE1364 standard is the bible that defines the correctness of the
Icarus Verilog implementation and behavior of the compiled
program. The IEEE1364.1 is also referenced for matters of
synthesis. So the ultimate definition of right and wrong comes from
those documents.
That does not mean that a Verilog implementation is fully
constrained. The standard document allows for implementation specific
behavior that, when properly accounted for, does not effect the
intended semantics of the specified language. It is therefore possible
and common to write programs that produce different results when run
by different Verilog implementations.
STANDARDIZATION ISSUES
These are some issues where the IEEE1364 left unclear, unspecified or
simply wrong. I'll try to be precise as I can, and reference the
standard as needed. I've made implementation decisions for Icarus
Verilog, and I will make clear what those decisions are and how they
affect the language.
* OBJECTS CAN BE DECLARED ANYWHERE IN THE MODULE
Consider this module:
module sample1;
initial foo = 1;
reg foo;
wire tmp = bar;
initial #1 $display("foo = %b, bar = %b", foo, tmp);
endmodule
Notice that the ``reg foo;'' declaration is placed after the first
initial statement. It turns out that this is a perfectly legal module
according to the -1995 and -2000 versions of the standard. The
statement ``reg foo;'' is a module_item_declaration which is in turn a
module_item. The BNF in the appendix of IEEE1364-1995 treats all
module_item statements equally, so no order is imposed.
Furthermore, there is no text (that I can find) elsewhere in the
standard that imposes any ordering restriction. The sorts of
restrictions I would look for are "module_item_declarations must
appear before all other module_items" or "variables must be declared
textually before they are referenced." Such statements simply do not
exist. (Personally, I think it is fine that they don't.)
The closest is the rules for implicit declarations of variables that
are otherwise undeclared. In the above example, ``bar'' is implicitly
declared and is therefore a wire. However, although ``initial foo = 1;''
is written before foo is declared, foo *is* declared within the
module, and declared legally by the BNF of the standard.
Here is another example:
module sample2;
initial x.foo = 1;
test x;
initial #1 $display("foo = %b", x.foo);
endmodule
module test;
reg foo;
endmodule;
From this example one can clearly see that foo is once again declared
after its use in behavioral code. One also sees a forward reference of
an entire module. Once again, the standard places no restriction on
the order of module declarations in a source file, so this program is,
according to the standard, perfectly well formed.
Icarus Verilog interprets both of these examples according to "The
Standard As I Understand It." However, commercial tools in general
break down with these programs. In particular, the first example
may generate different errors depending on the tool. The most common
error is to claim that ``foo'' is declared twice, once (implicitly) as
a wire and once as a reg.
So the question now becomes, "Is the standard broken, or are the tools
limited?" Coverage of the standard seems to vary widely from tool to
tool so it is not clear that the standard really is at fault. It is
clear, however, that somebody goofed somewhere.
My personal opinion is that there is no logical need to require that
all module_item_declarations preceed any other module items. I
personally would oppose such a restriction. It may make sense to
require that declarations of variables within a module be preceded by
their use, although even that is not necessary for the implementation
of efficient compilers.
However, the existence hierarchical naming syntax as demonstrated in
sample2 can have implications that affect any declaration order
rules. When reaching into a module with a hierarchical name, the
module being referenced is already completely declared (or not
declared at all, as in sample2) so module_item order is completely
irrelevent. But a "declare before use" rule would infect module
ordering, by requiring that modules that are used be first defined.
$Id: ieee1364-notes.txt,v 1.1 2000/07/23 18:06:31 steve Exp $
$Log: ieee1364-notes.txt,v $
Revision 1.1 2000/07/23 18:06:31 steve
Document ieee1364 issues.
-55
View File
@@ -1,55 +0,0 @@
# The iverilog.conf configuration file provides to the iverilog driver
# strings based on switches that are passed by the user on the command
# line.
#
# Comments start from the hash (#) character and run to the end of the
# line.
#
# Conditions are a list of requirements between [] characters. For the
# set of patterns following a string to b activated, all the
# conditions must be true. Valid conditions are:
#
# -S -- The -S flag is passed to iverilog
# -t<string> -- The -t<string> parameters is passed to iverilog
#
#
# Patterns have a name and text. The name has the form <key> where the
# key is some key value that is required by iverilog. The commonly
# used keys are:
#
# <ivl>
# The string here is the command line needed to take the
# preprocessor output (ivlpp) and compile it with the
# target. All target types use this key.
#
# The pattern text includes %<code> substitutions. iverilog
# substitutes values for the %<code> sequences within the text.
#
# %B Substitute the base libdir, -B flag of iverilog.
#
# %s Substitute the start module (-s flag) from the user.
#
# %N Substitute the value of the -N<path> flag.
#
# %T Substitute min, typ or max depending on the -T flag from the
# command line.
#
# %?<c><text>;
# This substitution pattern is magical, and is the only
# multicharacter pattern. This tests the code <c>, and
# substitutes <text> into the output only if <c> is true.
# The <text> may include further substitution strings, and is
# terminated by a semi-colon (;) character.
# This is the null (no op) target. Thre is a synthesis version and a
# non-synthesis version. Normally, this does not matter, but this can
# be useful and interesting if the -N flag is included.
[-tnull -S]
<ivl>%B/ivl %?s-s%s; %?N-N%N; %?T-T%T; -tnull -- -
[-tnull]
<ivl>%B/ivl %?s-s%s; %?N-N%N; %?T-T%T; -tnull -- -
-524
View File
@@ -1,524 +0,0 @@
#ifndef __ivl_target_H
#define __ivl_target_H
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: ivl_target.h,v 1.19 2000/10/13 03:39:27 steve Exp $"
#endif
#ifdef __cplusplus
#define _BEGIN_DECL extern "C" {
#define _END_DECL }
#else
#define _BEGIN_DECL
#define _END_DECL
#endif
_BEGIN_DECL
/*
* This header file describes the API for the loadable target
* module. The main program can load these modules and access the
* functions within the loaded module to implement the backend
* behavior.
*
* The interface is divided into two parts: the entry points within
* the core that are called by the module, and the entry points in
* the module that are called by the core. It is the latter that
* causes the module to be invoked in the first place, but most of the
* interesting information about the design is accessed through the
* various access functions that the modules calls into the core.
*/
/*
* In order to grab onto data in the design, the core passes cookies
* to the various functions of the module. These cookies can in turn
* be passed to access functions in the core to get more detailed
* information.
*
* The following typedefs list the various cookies that may be passed
* around.
*
* ivl_design_t
* This object represents the entire elaborated design. Various
* global properties and methods are available from this.
*
* ivl_expr_t
* This object represents a node of an expression. If the
* expression has sub-expressions, they can be accessed from
* various method described below. The ivl_expr_type method in
* particular gets the type of the node in the form of an
* ivl_expr_type_t enumeration value.
*
* Objects of this type represent expressions in
* processes. Structural expressions are instead treated as logic
* gates.
*
* ivl_net_logic_t
* This object represents various built in logic devices. In fact,
* this includes just about every directional device that has a
* single output, including logic gates and nmos, pmos and cmon
* devices. There is also the occasional Icarus Verilog creation.
*
* ivl_process_t
* A Verilog process is represented by one of these. A process may
* be an "initial" or an "always" process. These come from initial
* or always statements from the verilog source.
*
* ivl_scope_t
* Elaborated scopes within a design are represented by this
* type. Objects of this type also act as containers for scoped
* objects such as signals.
*
* ivl_statement_t
* Statements within processes are represented by one of these. The
* ivl_process_t object holds one of these, but a statement may in
* turn contain other statements.
*
* -- A Note About Bit Sets --
* Some objects hold a value as an array of bits. In these cases there
* is some method that retrieves the width of the value and another
* that returns a "char*". The latter is a pointer to the least
* significant bit value. Bit values are represented by the characters
* '0', '1', 'x' and 'z'. Strengths are stored elsewhere.
*
* -- A Note About Names --
* The names of objects are complete, hierarchical names. That is,
* they include the instance name of the module that contains them.
*/
typedef struct ivl_design_s *ivl_design_t;
typedef struct ivl_expr_s *ivl_expr_t;
typedef struct ivl_net_const_s*ivl_net_const_t;
typedef struct ivl_net_event_s*ivl_net_event_t;
typedef struct ivl_net_logic_s*ivl_net_logic_t;
typedef struct ivl_net_probe_s*ivl_net_probe_t;
typedef struct ivl_nexus_s *ivl_nexus_t;
typedef struct ivl_process_s *ivl_process_t;
typedef struct ivl_scope_s *ivl_scope_t;
typedef struct ivl_signal_s *ivl_signal_t;
typedef struct ivl_statement_s*ivl_statement_t;
/*
* These are types that are defined as enumerations. These have
* explicit values so that the binary API is a bit more resilient to
* changes and additions to the enumerations.
*/
/* This is the type of an ivl_expr_t object. */
typedef enum ivl_expr_type_e {
IVL_EX_NONE = 0,
IVL_EX_BINARY,
IVL_EX_NUMBER,
IVL_EX_SFUNC,
IVL_EX_SIGNAL,
IVL_EX_STRING,
IVL_EX_SUBSIG,
} ivl_expr_type_t;
/* This is the type code for an ivl_net_logic_t object. */
typedef enum ivl_logic_e {
IVL_LO_NONE = 0,
IVL_LO_AND,
IVL_LO_BUF,
IVL_LO_BUFIF0,
IVL_LO_BUFIF1,
IVL_LO_BUFZ,
IVL_LO_NAND,
IVL_LO_NOR,
IVL_LO_NOT,
IVL_LO_NOTIF0,
IVL_LO_NOTIF1,
IVL_LO_OR,
IVL_LO_XNOR,
IVL_LO_XOR
} ivl_logic_t;
/* Processes are initial or always blocks with a statement. This is
the type of the ivl_process_t object. */
typedef enum ivl_process_type_e {
IVL_PR_INITIAL = 0,
IVL_PR_ALWAYS = 1
} ivl_process_type_t;
/* Signals (ivl_signal_t) that are ports into the scope that contains
them have a port type. Otherwise, they are port IVL_SIP_NONE. */
typedef enum ivl_signal_port_e {
IVL_SIP_NONE = 0,
IVL_SIP_INPUT = 1,
IVL_SIP_OUTPUT= 2,
IVL_SIP_INOUT = 3
} ivl_signal_port_t;
/* This is the type code for an ivl_signal_t object. Implicit types
are resolved by the core compiler, and integers are converted into
signed registers. */
typedef enum ivl_signal_type_e {
IVL_SIT_NONE = 0,
IVL_SIT_REG,
IVL_SIT_SUPPLY0,
IVL_SIT_SUPPLY1,
IVL_SIT_TRI,
IVL_SIT_TRI0,
IVL_SIT_TRI1,
IVL_SIT_TRIAND,
IVL_SIT_TRIOR,
IVL_SIT_WAND,
IVL_SIT_WIRE,
IVL_SIT_WOR
} ivl_signal_type_t;
/* This is the type code for ivl_statement_t objects. */
typedef enum ivl_statement_type_e {
IVL_ST_NONE = 0,
IVL_ST_NOOP = 1,
IVL_ST_ASSIGN,
IVL_ST_BLOCK,
IVL_ST_CONDIT,
IVL_ST_DELAY,
IVL_ST_DELAYX,
IVL_ST_STASK,
IVL_ST_TRIGGER,
IVL_ST_WAIT,
IVL_ST_WHILE
} ivl_statement_type_t;
/* This function returns the string value of the named flag. The key
is used to select the flag. If the key does not exist or the flag
does not have a value, this function returns 0.
Flags come from the "-fkey=value" options to the iverilog command
line.
The key "-o" is special and is the argument to the -o flag of the
iverilog command. This is generally how the target learns the name
of the output file. */
extern const char* ivl_get_flag(ivl_design_t, const char*key);
/* Get the name of the root module. This can be used as the design name. */
extern const char* ivl_get_root_name(ivl_design_t net);
/*
* These methods apply to ivl_net_const_t objects.
*/
extern const char* ivl_const_bits(ivl_net_const_t net);
extern ivl_nexus_t ivl_const_pin(ivl_net_const_t net, unsigned idx);
extern unsigned ivl_const_pins(ivl_net_const_t net);
extern int ivl_const_signed(ivl_net_const_t net);
/* EXPRESSION
* These methods operate on expression objects from the
* design. Expressions mainly exist in behavioral code. The
* ivl_expr_type() function returns the type of the expression node,
* and the remaining functions access value bits of the expression.
*/
extern ivl_expr_type_t ivl_expr_type(ivl_expr_t net);
/* IVL_EX_NUMBER */
extern const char* ivl_expr_bits(ivl_expr_t net);
/* IVL_EX_SIGNAL, IVL_EX_SFUNC */
extern const char* ivl_expr_name(ivl_expr_t net);
/* IVL_EX_BINARY */
extern char ivl_expr_opcode(ivl_expr_t net);
/* IVL_EX_BINARY */
extern ivl_expr_t ivl_expr_oper1(ivl_expr_t net);
/* IVL_EX_BINARY */
extern ivl_expr_t ivl_expr_oper2(ivl_expr_t net);
/* */
extern ivl_expr_t ivl_expr_oper3(ivl_expr_t net);
/* any expression */
extern int ivl_expr_signed(ivl_expr_t net);
/* IVL_EX_STRING */
extern const char* ivl_expr_string(ivl_expr_t net);
/* any expression */
extern unsigned ivl_expr_width(ivl_expr_t net);
/* LOGIC
* These types and functions support manipulation of logic gates. The
* ivl_logic_t enumeration identifies the various kinds of gates that
* the ivl_net_logic_t can represent. The various functions then
* provide access to the bits of information for a given logic device.
*/
extern ivl_logic_t ivl_logic_type(ivl_net_logic_t net);
extern ivl_nexus_t ivl_logic_pin(ivl_net_logic_t net, unsigned pin);
extern unsigned ivl_logic_pins(ivl_net_logic_t net);
/* NEXUS
* connections of signals and nodes is handled by single-bit
* nexus. These functions manage the ivl_nexus_t object.
*/
extern const char* ivl_nexus_name(ivl_nexus_t net);
/* SCOPE
* Scopes of various sort have these properties. Use these methods to
* access them.
*/
extern const char* ivl_scope_name(ivl_scope_t net);
/* SIGNALS
* Signals are named things in the Verilog source, like wires and
* regs, and also named things that are preated as temporaries during
* certain elaboration or optimization steps. A signal may also be a
* port of a module or task.
*
* Signals have a name (obviously) and types. A signal may also be
* signed or unsigned.
*/
extern unsigned ivl_signal_pins(ivl_signal_t net);
extern ivl_signal_port_t ivl_signal_port(ivl_signal_t net);
extern ivl_signal_type_t ivl_signal_type(ivl_signal_t net);
extern const char* ivl_signal_name(ivl_signal_t net);
extern const char* ivl_signal_basename(ivl_signal_t net);
/*
* These functions get information about a process. A process is
* an initial or always block within the original Verilog source, that
* is translated into a type and a single statement. (The statement
* may be a compound statement.)
*
* The ivl_process_type function gets the type of the process,
* an "inital" or "always" statement.
*
* The ivl_process_stmt function gets the statement that forms the
* process. See the statement related functions for how to manipulate
* statements.
*/
extern ivl_process_type_t ivl_process_type(ivl_process_t net);
extern ivl_statement_t ivl_process_stmt(ivl_process_t net);
/*
* These functions manage statements of various type. This includes
* all the different kinds of statements (as enumerated in
* ivl_statement_type_t) that might occur in behavioral code.
*
* The ivl_statement_type() function returns the type code for the
* statement. This is the major type, and implies which of the later
* functions are applicable to the statemnt.
*/
extern ivl_statement_type_t ivl_statement_type(ivl_statement_t net);
/*
* The following functions retrieve specific single values from the
* statement. These values are the bits of data and parameters that
* make up the statement. Many of these functions apply to more then
* one type of statement, so the comment in front of them tells which
* statement types can be passed to the function.
*/
/* IVL_ST_BLOCK */
extern unsigned ivl_stmt_block_count(ivl_statement_t net);
/* IVL_ST_BLOCK */
extern ivl_statement_t ivl_stmt_block_stmt(ivl_statement_t net, unsigned i);
/* IVL_ST_CONDIT */
extern ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net);
/* IVL_ST_CONDIT */
extern ivl_statement_t ivl_stmt_cond_false(ivl_statement_t net);
/* IVL_ST_CONDIT */
extern ivl_statement_t ivl_stmt_cond_true(ivl_statement_t net);
/* IVL_ST_DELAY */
extern unsigned long ivl_stmt_delay_val(ivl_statement_t net);
/* IVL_ST_ASSIGN */
extern unsigned ivl_stmt_lwidth(ivl_statement_t net);
/* IVL_ST_STASK */
extern const char* ivl_stmt_name(ivl_statement_t net);
/* IVL_ST_STASK */
extern ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx);
/* IVL_ST_STASK */
extern unsigned ivl_stmt_parm_count(ivl_statement_t net);
/* IVL_ST_ASSIGN */
extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net);
/* IVL_ST_DELAY, IVL_ST_WAIT, IVL_ST_WHILE */
extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
/* TARGET MODULE ENTRY POINTS
*
* These are not functions in the API but functions that the target
* module supplies. They are presented as typedefs of functions (which
* are used internally) but the target module makes them work by
* exporting them.
*
* The module entry points generally take a cookie and possibly a name
* as parameters. They use the cookie to get the required detailed
* information, and they do their job. The functions return an integer
* value which usually should be 0 for success, or less then 0 for any
* errors. How the error is interpreted depends on the function
* returning the error.
*/
/* target_start_design (required)
The "target_start_design" function is called once before
any other functions in order to start the processing of the
netlist. The function returns a value <0 if there is an error. */
typedef int (*start_design_f)(ivl_design_t des);
/* target_end_design (required)
The target_end_design function in the loaded module is called once
to clean up (for example to close files) from handling of the
netlist. */
typedef void (*end_design_f)(ivl_design_t des);
/* target_net_const (optional)
The "target_net_const" function is called for structural constant
values that appear in the design. */
typedef int (*net_const_f)(const char*name, ivl_net_const_t net);
/* target_net_event
Verilog code such as @event and @(posedge foo) create event
objects. These named objects can be triggered by structural probes
or behavioral triggers. The target_net_event function is called
once for each event in the netlist. The event function is
guaranteed to be called before probe or trigger functions. */
typedef int (*net_event_f)(const char*name, ivl_net_event_t net);
/* target_net_logic
This function is called for each logic gate in the design. The name
parameter is the name of the gate in the design. If the gate is
part of an array of gates, the name includes its index. */
typedef int (*net_logic_f)(const char*name, ivl_net_logic_t net);
/* target_net_probe
This is the probe, or structural trigger, of an event. The
net_event_f is guaranteed to be called for the associated event
before this probe is called. */
typedef int (*net_probe_f)(const char*name, ivl_net_probe_t net);
/* target_net_signal
Signals are things like "wire foo" or "reg bar;" that is, declared
signals in the verilog source. These are not memories, which are
handled elsewhere. */
typedef int (*net_signal_f)(const char*name, ivl_signal_t net);
/* target_process
The "target_process" function is called for each always and initial
block in the design. In principle, the target creates a thread for
each process in the Verilog original.
This function is called with the entire thread generated. The
process and statement access methods can be used to randomly
(read-only) access all the code of the thread. Also, the module may
hold on to the process, the core will not delete it. */
typedef int (*process_f)(ivl_process_t net);
/* target_scope (optional)
If the "target_scope" function is implemented in the module, it is
called to introduce a new scope in the design. If scopes are
nested, this method is always called for the containing scope
before the contained scope. Also, this is guaranteed to be called
before functions for any objects contained in this scope. */
typedef void (*scope_f)(ivl_scope_t net);
_END_DECL
/*
* $Log: ivl_target.h,v $
* Revision 1.19 2000/10/13 03:39:27 steve
* Include constants in nexus targets.
*
* Revision 1.18 2000/10/08 04:01:54 steve
* Back pointers in the nexus objects into the devices
* that point to it.
*
* Collect threads into a list in the design.
*
* Revision 1.17 2000/10/07 19:45:43 steve
* Put logic devices into scopes.
*
* Revision 1.16 2000/10/06 23:46:50 steve
* ivl_target updates, including more complete
* handling of ivl_nexus_t objects. Much reduced
* dependencies on pointers to netlist objects.
*
* Revision 1.15 2000/10/05 05:03:01 steve
* xor and constant devices.
*
* Revision 1.14 2000/09/30 02:18:15 steve
* ivl_expr_t support for binary operators,
* Create a proper ivl_scope_t object.
*
* Revision 1.13 2000/09/26 00:30:07 steve
* Add EX_NUMBER and ST_TRIGGER to dll-api.
*
* Revision 1.12 2000/09/24 15:46:00 steve
* API access to signal type and port type.
*
* Revision 1.11 2000/09/24 02:21:53 steve
* Add support for signal expressions.
*
* Revision 1.10 2000/09/23 05:15:07 steve
* Add enough tgt-verilog code to support hello world.
*
* Revision 1.9 2000/09/22 03:58:30 steve
* Access to the name of a system task call.
*
* Revision 1.8 2000/09/19 04:15:27 steve
* Introduce the means to get statement types.
*
* Revision 1.7 2000/09/18 01:24:32 steve
* Get the structure for ivl_statement_t worked out.
*
* Revision 1.6 2000/08/27 15:51:50 steve
* t-dll iterates signals, and passes them to the
* target module.
*
* Some of NetObj should return char*, not string.
*
* Revision 1.5 2000/08/26 00:54:03 steve
* Get at gate information for ivl_target interface.
*
* Revision 1.4 2000/08/20 04:13:57 steve
* Add ivl_target support for logic gates, and
* make the interface more accessible.
*
* Revision 1.3 2000/08/19 18:12:42 steve
* Add target calls for scope, events and logic.
*
* Revision 1.2 2000/08/14 04:39:56 steve
* add th t-dll functions for net_const, net_bufz and processes.
*
* Revision 1.1 2000/08/12 16:34:37 steve
* Start stub for loadable targets.
*
*/
#endif
+7 -6
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.7 2000/01/01 20:57:51 steve Exp $"
#ident "$Id: Makefile.in,v 1.6.2.1 1999/12/03 17:43:49 steve Exp $"
#
#
SHELL = /bin/sh
@@ -33,6 +33,7 @@ VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
libexecdir = $(libdir)/ivl
includedir = $(prefix)/include
CC = @CC@
@@ -60,16 +61,16 @@ lexor.c: lexor.lex
parse.h parse.c: parse.y
bison --verbose -t -d parse.y -o parse.c
install: all installdirs $(libdir)/ivl/ivlpp
install: all installdirs $(libexecdir)/ivlpp
$(libdir)/ivl/ivlpp: ivlpp
$(INSTALL_PROGRAM) ./ivlpp $(libdir)/ivl/ivlpp
$(libexecdir)/ivlpp: ivlpp
$(INSTALL_PROGRAM) ./ivlpp $(libexecdir)/ivlpp
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(libdir)/ivl
$(srcdir)/../mkinstalldirs $(bindir)
uninstall:
rm -f $(libdir)/ivl/ivlpp
rm -f $(bindir)/ivlpp
lexor.o: lexor.c parse.h globals.h
main.o: main.c globals.h
+3 -14
View File
@@ -18,14 +18,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: globals.h,v 1.5 2000/09/13 22:33:13 steve Exp $"
#if !defined(WINNT)
#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, char*paths[]);
extern void define_macro(const char*name, const char*value, int keyword);
extern void define_macro(const char*name, const char*value);
/* These variables contain the include directories to be searched when
an include directive in encountered. */
@@ -35,22 +35,11 @@ extern unsigned include_cnt;
/* This flag is true if #line directives are to be generated. */
extern int line_direct_flag;
extern unsigned error_count;
/* This is the entry to the parser. */
extern int yyparse();
/*
* $Log: globals.h,v $
* Revision 1.5 2000/09/13 22:33:13 steve
* undefined macros are null (with warnings.)
*
* Revision 1.4 2000/08/20 17:49:04 steve
* Clean up warnings and portability issues.
*
* Revision 1.3 2000/06/30 15:49:44 steve
* Handle errors from parser slightly differently.
*
* Revision 1.2 1999/09/05 22:33:18 steve
* Take multiple source files on the command line.
*
+14 -54
View File
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: lexor.lex,v 1.21 2000/09/13 22:33:13 steve Exp $"
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.14 1999/10/08 17:27:56 steve Exp $"
#endif
# include <stdio.h>
@@ -35,7 +35,6 @@ static void output_init();
static void def_match();
static void def_start();
static void def_finish();
static void def_undefine();
static void do_define();
static int is_defined(const char*name);
@@ -116,25 +115,13 @@ W [ \t\b\f]+
that follows it. when the directive ends, the do_include function
performs the include operation. */
^{W}?`include { yy_push_state(PPINCLUDE); }
^{W}?`include { BEGIN(PPINCLUDE); }
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
<PPINCLUDE>[ \t\b\f] { ; }
/* Catch single-line comments that share the line with an include
directive. And while I'm at it, I might as well preserve the
comment in the output stream. */
<PPINCLUDE>"//".* { ECHO; }
/* These finish the include directive (EOF or EOL) so I revert the
lexor state and execute the inclusion. */
<PPINCLUDE>\n { istack->lineno += 1; yy_pop_state(); do_include(); }
<PPINCLUDE>\r\n { istack->lineno += 1; yy_pop_state(); do_include(); }
<PPINCLUDE>\n\r { istack->lineno += 1; yy_pop_state(); do_include(); }
<PPINCLUDE><<EOF>> { istack->lineno += 1; yy_pop_state(); do_include(); }
<PPINCLUDE>\n { istack->lineno += 1; BEGIN(0); do_include(); }
/* Detect the define directive, and match the name. Match any
@@ -142,22 +129,13 @@ 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}? { yy_push_state(PPDEFINE); def_start(); }
`define{W}[a-zA-Z][a-zA-Z0-9_]*{W}? { BEGIN(PPDEFINE); def_start(); }
<PPDEFINE>.* { do_define(); }
<PPDEFINE>(\n|"\r\n"|"\n\r") {
def_finish();
<PPDEFINE>.*\n {
do_define();
istack->lineno += 1;
fputc('\n', yyout);
yy_pop_state();
}
<PPDEFINE><<EOF>> {
def_finish();
istack->lineno += 1;
fputc('\n', yyout);
yy_pop_state();
BEGIN(0);
}
`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
@@ -216,8 +194,6 @@ W [ \t\b\f]+
struct define_t {
char*name;
char*value;
/* keywords don't get rescanned for fresh values. */
int keyword;
struct define_t*left, *right, *up;
};
@@ -257,14 +233,8 @@ static void def_match()
struct define_t*cur = def_lookup(yytext+1);
if (cur) {
struct include_stack_t*isp;
if (cur->keyword) {
fprintf(yyout, "%s", cur->value);
return;
}
isp = calloc(1, sizeof(struct include_stack_t));
struct include_stack_t*isp
= calloc(1, sizeof(struct include_stack_t));
isp->str = cur->value;
isp->next = istack;
istack->yybs = YY_CURRENT_BUFFER;
@@ -272,9 +242,7 @@ static void def_match()
yy_switch_to_buffer(yy_new_buffer(istack->file, YY_BUF_SIZE));
} else {
fprintf(stderr, "%s:%u: warning: macro %s undefined "
"(and assumed null) at this point.\n",
istack->path, istack->lineno, yytext);
fprintf(yyout, "%s", yytext);
}
}
@@ -285,12 +253,11 @@ static void def_start()
sscanf(yytext, "`define %s", def_name);
}
void define_macro(const char*name, const char*value, int keyword)
void define_macro(const char*name, const char*value)
{
struct define_t*def = malloc(sizeof(struct define_t));
def->name = strdup(name);
def->value = strdup(value);
def->keyword = keyword;
def->left = 0;
def->right = 0;
def->up = 0;
@@ -350,14 +317,7 @@ static void do_define()
*cp = 0;
}
define_macro(def_name, yytext, 0);
def_name[0] = 0;
}
static void def_finish()
{
if (def_name[0])
define_macro(def_name, "1", 0);
define_macro(def_name, yytext);
}
static void def_undefine()
@@ -562,7 +522,7 @@ static int yywrap()
if (line_direct_flag)
fprintf(yyout, "\n#line \"%s\" 0\n", istack->path);
yyrestart(istack->file);
yyrestart(isp->file);
return 0;
}
+5 -47
View File
@@ -16,8 +16,8 @@ const char COPYRIGHT[] =
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: main.c,v 1.7 2000/09/13 22:33:13 steve Exp $"
#if !defined(WINNT)
#ident "$Id: main.c,v 1.4 1999/11/29 17:02:21 steve Exp $"
#endif
const char NOTICE[] =
@@ -52,8 +52,6 @@ unsigned include_cnt = 0;
int line_direct_flag = 0;
unsigned error_count = 0;
int main(int argc, char*argv[])
{
int opt;
@@ -61,29 +59,11 @@ int main(int argc, char*argv[])
char*out_path = 0;
FILE*out;
/* Define preprocessor keywords that I plan to just pass. */
define_macro("celldefine", "`celldefine", 1);
define_macro("default_nettype", "`default_nettype", 1);
define_macro("delay_mode_distributed", "`delay_mode_distributed", 1);
define_macro("delay_mode_unit", "`delay_mode_unit", 1);
define_macro("delay_mode_path", "`delay_mode_path", 1);
define_macro("disable_portfaults", "`enable_portfaults", 1);
define_macro("endcelldefine", "`endcelldefine", 1);
define_macro("endprotect", "`endprotect", 1);
define_macro("nosuppress_faults", "`nosuppress_faults", 1);
define_macro("nounconnected_drive", "`nounconnected_drive", 1);
define_macro("protect", "`protect", 1);
define_macro("resetall", "`resetall", 1);
define_macro("suppress_faults", "`suppress_faults", 1);
define_macro("timescale", "`timescale", 1);
define_macro("unconnected_drive", "`unconnected_drive", 1);
define_macro("uselib", "`uselib", 1);
include_dir = malloc(sizeof(char*));
include_dir[0] = strdup(".");
include_cnt = 1;
while ((opt = getopt(argc, argv, "D:I:K:Lo:v")) != EOF) switch (opt) {
while ((opt = getopt(argc, argv, "D:I:Lo:v")) != EOF) switch (opt) {
case 'D': {
char*tmp = strdup(optarg);
@@ -93,7 +73,7 @@ int main(int argc, char*argv[])
else
val = "1";
define_macro(tmp, val, 0);
define_macro(tmp, val);
free(tmp);
break;
}
@@ -104,15 +84,6 @@ int main(int argc, char*argv[])
include_cnt += 1;
break;
case 'K': {
char*buf = malloc(strlen(optarg) + 2);
buf[0] = '`';
strcpy(buf+1, optarg);
define_macro(optarg, buf, 1);
free(buf);
break;
}
case 'L':
line_direct_flag = 1;
break;
@@ -144,7 +115,6 @@ int main(int argc, char*argv[])
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"
" -K<def> - Define a keyword macro that I just pass\n"
" -L - Emit line number directives\n"
" -o<fil> - Send the output to <fil>\n"
" -v - Print version information\n",
@@ -168,23 +138,11 @@ int main(int argc, char*argv[])
}
reset_lexor(out, argv+optind);
if (yyparse()) return -1;
return error_count;
return yyparse();
}
/*
* $Log: main.c,v $
* Revision 1.7 2000/09/13 22:33:13 steve
* undefined macros are null (with warnings.)
*
* Revision 1.6 2000/08/20 17:49:05 steve
* Clean up warnings and portability issues.
*
* Revision 1.5 2000/06/30 15:49:44 steve
* Handle errors from parser slightly differently.
*
* Revision 1.4 1999/11/29 17:02:21 steve
* include getopt if present.
*
+2 -2
View File
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: parse.y,v 1.2 2000/08/20 17:49:05 steve Exp $"
#if !defined(WINNT)
#ident "$Id: parse.y,v 1.1 1999/07/03 17:24:11 steve Exp $"
#endif
static void yyerror(const char*msg);
+47 -250
View File
@@ -1,7 +1,7 @@
%{
/*
* Copyright (c) 1998-2000 Stephen Williams ([email protected])
* Copyright (c) 1998-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
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: lexor.lex,v 1.50 2000/10/14 16:48:59 steve Exp $"
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.38 1999/11/23 02:49:04 steve Exp $"
#endif
//# define YYSTYPE lexval
@@ -30,7 +30,6 @@
# include "parse.h"
# include <ctype.h>
# include <string.h>
# include "lexor_keyword.h"
extern FILE*vl_input;
extern string vl_file;
@@ -39,12 +38,11 @@ extern string vl_file;
# define yylval VLlval
extern YYLTYPE yylloc;
extern void pform_set_timescale(int, int);
static void reset_lexor();
static void line_directive();
static void line_directive2();
extern int check_identifier(const char*str, int len);
static verinum*make_sized_binary(const char*txt);
static verinum*make_sized_dec(const char*txt);
static verinum*make_unsized_dec(const char*txt);
@@ -55,8 +53,6 @@ static verinum*make_unsized_dec(const char*txt);
static verinum*make_unsized_octal(const char*txt);
static verinum*make_unsized_hex(const char*txt);
static void process_timescale(const char*txt);
static int comment_enter;
%}
@@ -101,7 +97,6 @@ W [ \t\b\f\r]+
"~^" { return K_NXOR; }
"^~" { return K_NXOR; }
"~&" { return K_NAND; }
"->" { return K_TRIGGER; }
[}{;:\[\],()#=.@&!?<>%|^~+*/-] { return yytext[0]; }
@@ -111,7 +106,6 @@ W [ \t\b\f\r]+
<CSTRING>\n { BEGIN(0);
yylval.text = strdup(yytext);
VLerror(yylloc, "Missing close quote of string.");
yylloc.first_line += 1;
return STRING; }
<CSTRING>\" { BEGIN(0);
yylval.text = strdup(yytext);
@@ -119,16 +113,16 @@ W [ \t\b\f\r]+
return STRING; }
<CSTRING>. { yymore(); }
<UDPTABLE>\(\?0\) { return '_'; }
<UDPTABLE>\(\?1\) { return '+'; }
<UDPTABLE>\(\?[xX]\) { return '%'; }
<UDPTABLE>\(\?\?\) { return '*'; }
<UDPTABLE>\(01\) { return 'r'; }
<UDPTABLE>\(0[xX]\) { return 'P'; }
<UDPTABLE>\(10\) { return 'f'; }
<UDPTABLE>\(1[xX]\) { return 'N'; }
<UDPTABLE>\([xX]0\) { return 'F'; }
<UDPTABLE>\([xX]1\) { return 'R'; }
<UDPTABLE>\(\?0\) { return '_'; }
<UDPTABLE>\(\?1\) { return '+'; }
<UDPTABLE>\(\?x\) { return '%'; }
<UDPTABLE>\(\?\?\) { return '*'; }
<UDPTABLE>\(01\) { return 'r'; }
<UDPTABLE>\(0x\) { return 'P'; }
<UDPTABLE>\(10\) { return 'f'; }
<UDPTABLE>\(1x\) { return 'N'; }
<UDPTABLE>\(x0\) { return 'F'; }
<UDPTABLE>\(x1\) { return 'R'; }
<UDPTABLE>[bB] { return 'b'; }
<UDPTABLE>[fF] { return 'f'; }
<UDPTABLE>[rR] { return 'r'; }
@@ -136,15 +130,13 @@ W [ \t\b\f\r]+
<UDPTABLE>[pPnN01\?\*\-] { return yytext[0]; }
[a-zA-Z_][a-zA-Z0-9$_]* {
int rc = lexor_keyword_code(yytext, yyleng);
int rc = check_identifier(yytext, yyleng);
if (rc == IDENTIFIER)
yylval.text = strdup(yytext);
else
yylval.text = 0;
return rc;
}
return rc; }
[a-zA-Z_][a-zA-Z0-9$_]*(\.[a-zA-Z_][a-zA-Z0-9$_]*)+ {
yylval.text = strdup(yytext);
@@ -167,26 +159,26 @@ W [ \t\b\f\r]+
yylval.text = strdup(cp);
return PORTNAME; }
[0-9][0-9_]*[ \t]*\'[sS]?[dD][ \t]*[0-9][0-9_]* {
[0-9][0-9_]*[ \t]*\'[dD][ \t]*[0-9][0-9_]* {
yylval.number = make_sized_dec(yytext);
return NUMBER; }
[0-9][0-9_]*[ \t]*\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ {
[0-9][0-9_]*[ \t]*\'[bB][ \t]*[0-1xzXZ_\?]+ {
yylval.number = make_sized_binary(yytext);
return NUMBER; }
[0-9][0-9_]*[ \t]*\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ {
[0-9][0-9_]*[ \t]*\'[oO][ \t]*[0-7xzXZ_\?]+ {
yylval.number = make_sized_octal(yytext);
return NUMBER; }
[0-9][0-9_]*[ \t]*\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ {
[0-9][0-9_]*[ \t]*\'[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ {
yylval.number = make_sized_hex(yytext);
return NUMBER; }
\'[sS]?[dD][ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext);
return NUMBER; }
\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext);
\'d[ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext);
return NUMBER; }
\'[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext);
return NUMBER; }
\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext);
\'[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext);
return NUMBER; }
\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext);
\'[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext);
return NUMBER; }
[0-9][0-9_]* {
@@ -206,7 +198,6 @@ W [ \t\b\f\r]+
}
yylval.number = new verinum(bits, nbits, false);
yylval.number->has_sign(true);
delete[]bits;
return NUMBER; }
@@ -222,8 +213,10 @@ W [ \t\b\f\r]+
/* Notice and handle the timescale directive. */
`timescale { BEGIN(PPTIMESCALE); }
<PPTIMESCALE>.* { process_timescale(yytext); }
<PPTIMESCALE>. { ; }
<PPTIMESCALE>\n {
cerr << yylloc.text << ":" << yylloc.first_line
<< ": Sorry, `timescale not supported." << endl;
yylloc.first_line += 1;
BEGIN(0); }
@@ -241,11 +234,11 @@ W [ \t\b\f\r]+
^`endcelldefine{W}?.* { }
^`endprotect{W}?.* { }
^`nosuppress_faults{W}?.* { }
^`nounconnected_drive{W}?.* { }
^`nounconnected_drive{W}?* { }
^`protect{W}?.* { }
^`resetall{W}?.* { }
^`suppress_faults{W}?.* { }
^`unconnected_drive{W}?.* { }
^`unconnected_drive{W}?* { }
^`uselib{W}?.* { }
@@ -319,27 +312,22 @@ void lex_end_table()
static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
{
bool sign_flag = false;
verinum::V*bits = new verinum::V[size];
if (tolower(ptr[0]) == 's') {
ptr += 1;
sign_flag = true;
}
assert(tolower(*ptr) == 'b');
ptr += 1;
verinum::V*bits = new verinum::V[size];
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
unsigned idx = 0;
const char*eptr = ptr + strlen(ptr) - 1;
while ((eptr > ptr) && (idx < size)) {
while ((eptr >= ptr) && (idx < size)) {
if (*eptr == '_') {
eptr -= 1;
continue;
}
switch (*eptr) {
case '_':
break;
case '0':
bits[idx++] = verinum::V0;
break;
@@ -358,22 +346,10 @@ static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
eptr -= 1;
}
/* If we filled up the expected number of bits, but there are
still characters of the number part left, then report a
warning that we are truncating. */
if ((idx >= size) && (eptr >= ptr))
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric binary constant ``" << ptr <<
"'' truncated to " << size << " bits." << endl;
// Zero-extend binary number, except that z or x is extended
// if it is the highest supplied digit.
while (idx < size) {
switch (ptr[0]) {
switch (ptr[1]) {
case '0':
case '1':
bits[idx++] = verinum::V0;
@@ -389,10 +365,7 @@ static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
}
}
verinum*out = new verinum(bits, size, fixed);
delete[]bits;
out->has_sign(sign_flag);
return out;
return new verinum(bits, size, fixed);
}
static verinum*make_sized_binary(const char*txt)
@@ -403,21 +376,16 @@ static verinum*make_sized_binary(const char*txt)
ptr += 1;
assert(*ptr == '\'');
ptr += 1;
assert(tolower(*ptr) == 'b');
return make_binary_with_size(size, true, ptr);
}
static verinum*make_unsized_binary(const char*txt)
{
bool sign_flag = false;
const char*ptr = txt;
assert(*ptr == '\'');
ptr += 1;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'b');
while (*ptr && ((*ptr == 'b') || (*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
@@ -452,29 +420,18 @@ static verinum*make_unsized_binary(const char*txt)
ptr += 1;
}
verinum*out = new verinum(bits, size);
out->has_sign(sign_flag);
delete[]bits;
return out;
return new verinum(bits, size);
}
static verinum*make_sized_octal(const char*txt)
{
bool sign_flag = false;
char*ptr;
unsigned size = strtoul(txt,&ptr,10);
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
assert(*ptr == '\'');
ptr += 1;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'o');
ptr += 1;
/* We know from the size number how bit to make the verinom
array, so make it now. */
@@ -487,11 +444,6 @@ static verinum*make_sized_octal(const char*txt)
/* Find the end of the digits. ptr already points to the start. */
char*eptr = ptr + strlen(ptr);
if ((strlen(ptr) * 3) > ((size+2)/3) * 3)
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric octal constant ``" << ptr <<
"'' truncated to " << size << " bits." << endl;
/* 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. */
@@ -554,24 +506,14 @@ static verinum*make_sized_octal(const char*txt)
}
}
verinum*out = new verinum(bits, size, true);
delete[]bits;
out->has_sign(sign_flag);
return out;
return new verinum(bits, size, true);
}
static verinum*make_unsized_octal(const char*txt)
{
bool sign_flag = false;
const char*ptr = txt;
assert(*ptr == '\'');
ptr += 1;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'o');
ptr += 1;
@@ -613,15 +555,11 @@ static verinum*make_unsized_octal(const char*txt)
ptr += 1;
}
verinum*out = new verinum(bits, size);
out->has_sign(sign_flag);
delete[]bits;
return out;
return new verinum(bits, size);
}
static verinum*make_sized_hex(const char*txt)
{
bool sign_flag = false;
char*ptr;
unsigned size = strtoul(txt,&ptr,10);
@@ -630,12 +568,6 @@ static verinum*make_sized_hex(const char*txt)
assert(*ptr == '\'');
ptr += 1;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'h');
ptr += 1;
@@ -690,15 +622,7 @@ static verinum*make_sized_hex(const char*txt)
eptr -= 1;
}
/* If we filled up the expected number of bits, but there are
still characters of the number part left, then report a
warning that we are truncating. */
if ((idx >= size) && (eptr >= ptr))
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric hex constant ``" << ptr <<
"'' truncated to " << size << " bits." << endl;
// zero extend hex numbers
// zero extend octal numbers
while (idx < size) switch (ptr[1]) {
case 'x': case 'X':
bits[idx++] = verinum::Vx;
@@ -710,23 +634,14 @@ static verinum*make_sized_hex(const char*txt)
bits[idx++] = verinum::V0;
}
verinum*out = new verinum(bits, size, true);
out->has_sign(sign_flag);
delete[]bits;
return out;
return new verinum(bits, size, true);
}
static verinum*make_unsized_hex(const char*txt)
{
bool sign_flag = false;
const char*ptr = txt;
assert(*ptr == '\'');
ptr += 1;
if (tolower(*ptr) == 's') {
sign_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'h');
ptr += 1;
@@ -779,10 +694,7 @@ static verinum*make_unsized_hex(const char*txt)
ptr += 1;
}
verinum*out = new verinum(bits, size);
out->has_sign(sign_flag);
delete[]bits;
return out;
return new verinum(bits, size);
}
/*
@@ -791,22 +703,12 @@ static verinum*make_unsized_hex(const char*txt)
*/
static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr)
{
bool signed_flag = false;
if (tolower(*ptr) == 's') {
signed_flag = true;
ptr += 1;
}
assert(tolower(*ptr) == 'd');
ptr += 1;
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
if ((strlen(ptr) * 4) > size)
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric decimal constant ``" << ptr <<
"'' truncated to " << size << " bits." << endl;
unsigned long value = 0;
for ( ; *ptr ; ptr += 1)
if (isdigit(*ptr)) {
@@ -824,10 +726,7 @@ static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr)
value /= 2;
}
verinum*out = new verinum(bits, size, fixed);
out->has_sign(signed_flag);
delete[]bits;
return out;
return new verinum(bits, size, fixed);
}
static verinum*make_sized_dec(const char*txt)
@@ -840,6 +739,7 @@ static verinum*make_sized_dec(const char*txt)
assert(*ptr == '\'');
ptr += 1;
assert(tolower(*ptr) == 'd');
return make_dec_with_size(size, true, ptr);
}
@@ -849,109 +749,6 @@ static verinum*make_unsized_dec(const char*txt)
return make_dec_with_size(INTEGER_WIDTH, false, txt+1);
}
/*
* The timescale parameter has the form:
* " <num> xs / <num> xs"
*/
static void process_timescale(const char*txt)
{
unsigned num;
const char*cp = txt + strspn(txt, " \t");
char*tmp;
const char*ctmp;
int unit = 0;
int prec = 0;
num = strtoul(cp, &tmp, 10);
if (num == 0) {
VLerror(yylloc, "Invalid timescale string.");
return;
}
while (num >= 10) {
unit += 1;
num /= 10;
}
if (num != 1) {
VLerror(yylloc, "Invalid timescale unit number.");
return;
}
cp = tmp;
cp += strspn(cp, " \t");
ctmp = cp + strcspn(cp, " \t/");
if (strncmp("s", cp, ctmp-cp) == 0) {
unit -= 0;
} else if (strncmp("ms", cp, ctmp-cp) == 0) {
unit -= 3;
} else if (strncmp("us", cp, ctmp-cp) == 0) {
unit -= 6;
} else if (strncmp("ns", cp, ctmp-cp) == 0) {
unit -= 9;
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
unit -= 12;
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
unit -= 15;
} else {
VLerror(yylloc, "Invalid timescale unit of measurement");
return;
}
cp = ctmp;
cp += strspn(cp, " \t/");
num = strtoul(cp, &tmp, 10);
if (num == 0) {
VLerror(yylloc, "Invalid timescale string.");
return;
}
assert(num);
while (num >= 10) {
prec += 1;
num /= 10;
}
if (num != 1) {
VLerror(yylloc, "Invalid timescale precision number.");
return;
}
cp = tmp;
cp += strspn(cp, " \t");
ctmp = cp + strcspn(cp, " \t\r");
if (strncmp("s", cp, ctmp-cp) == 0) {
prec -= 0;
} else if (strncmp("ms", cp, ctmp-cp) == 0) {
prec -= 3;
} else if (strncmp("us", cp, ctmp-cp) == 0) {
prec -= 6;
} else if (strncmp("ns", cp, ctmp-cp) == 0) {
prec -= 9;
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
prec -= 12;
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
prec -= 15;
} else {
VLerror(yylloc, "Invalid timescale precision units of measurement");
return;
}
pform_set_timescale(unit, prec);
}
static int yywrap()
{
+230
View File
@@ -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;
}
+5 -15
View File
@@ -4,10 +4,12 @@
#include "parse_misc.h"
#include "parse.h"
#include <string.h>
#include "lexor_keyword.h"
%}
struct lexor_keyword { const char*name; int tokenType; };
struct Keywords {
char *name;
int tokenType;
} Keywords;
%%
always, K_always
and, K_and
@@ -49,7 +51,6 @@ input, K_input
integer, K_integer
join, K_join
large, K_large
localparam, K_localparam
macromodule, K_macromodule
medium, K_medium
module, K_module
@@ -80,7 +81,6 @@ rtran, K_rtran
rtranif0, K_rtranif0
rtranif1, K_rtranif1
scalered, K_scalered
signed, K_signed
small, K_small
specify, K_specify
specparam, K_specparam
@@ -109,14 +109,4 @@ while, K_while
wire, K_wire
wor, K_wor
xnor, K_xnor
xor, K_xor
%%
int lexor_keyword_code(const char*str, unsigned nstr)
{
const struct lexor_keyword*rc = check_identifier(str, nstr);
if (rc == 0)
return IDENTIFIER;
else
return rc->tokenType;
}
xor, K_xor
-33
View File
@@ -1,33 +0,0 @@
#ifndef __lexor_keyword_H
#define __lexor_keyword_H
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: lexor_keyword.h,v 1.1 2000/03/12 17:09:41 steve Exp $"
#endif
extern int lexor_keyword_code (const char*str, unsigned len);
/*
* $Log: lexor_keyword.h,v $
* Revision 1.1 2000/03/12 17:09:41 steve
* Support localparam.
*
*/
#endif
-120
View File
@@ -1,120 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: link_const.cc,v 1.5 2000/07/14 06:12:57 steve Exp $"
#endif
# include "netlist.h"
# include "netmisc.h"
bool link_drivers_constant(const Link&lnk)
{
const Nexus*nex = lnk.nexus();
for (const Link*cur = nex->first_nlink()
; cur ; cur = cur->next_nlink()) {
if (cur == &lnk)
continue;
if (cur->get_dir() == Link::INPUT)
continue;
/* If the link is PASSIVE then it doesn't count as a
driver if its initial value is Vz. This is pertinant
because REGs are PASSIVE but can receive values from
procedural assignments. */
if ((cur->get_dir() == Link::PASSIVE)
&& (cur->get_init() == verinum::Vz))
continue;
if (! dynamic_cast<const NetConst*>(cur->get_obj()))
return false;
}
return true;
}
verinum::V driven_value(const Link&lnk)
{
const Nexus*nex = lnk.nexus();
for (const Link*cur = nex->first_nlink()
; cur ; cur = cur->next_nlink()) {
const NetConst*obj;
if (obj = dynamic_cast<const NetConst*>(cur->get_obj()))
return obj->value(cur->get_pin());
}
return lnk.get_init();
}
NetConst* link_const_value(Link&pin, unsigned&idx)
{
NetConst*robj = 0;
unsigned ridx = 0;
Nexus*nex = pin.nexus();
for (Link*cur = nex->first_nlink()
; cur ; cur = cur->next_nlink()) {
NetConst*tmp;
if ((tmp = dynamic_cast<NetConst*>(cur->get_obj())) == 0)
continue;
if (robj != 0)
continue;
robj = tmp;
ridx = cur->get_pin();
}
idx = ridx;
return robj;
}
/*
* $Log: link_const.cc,v $
* Revision 1.5 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.4 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
* Revision 1.3 2000/05/14 17:55:04 steve
* Support initialization of FF Q value.
*
* Revision 1.2 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.1 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
*/
+31 -97
View File
@@ -1,6 +1,6 @@
const char COPYRIGHT[] =
"Copyright (c) 1998-2000 Stephen Williams ([email protected])";
"Copyright (c) 1998-1999 Stephen Williams ([email protected])";
/*
* This source code is free software; you can redistribute it
@@ -18,8 +18,8 @@ const char COPYRIGHT[] =
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: main.cc,v 1.38 2000/09/12 01:17:40 steve Exp $"
#if !defined(WINNT)
#ident "$Id: main.cc,v 1.26 1999/11/29 17:02:21 steve Exp $"
#endif
const char NOTICE[] =
@@ -50,7 +50,6 @@ const char NOTICE[] =
# include "pform.h"
# include "netlist.h"
# include "target.h"
# include "compiler.h"
const char VERSION[] = "$Name: $ $State: Exp $";
@@ -59,12 +58,6 @@ string start_module = "";
map<string,string> flags;
/*
* These are the warning enable flags.
*/
bool warn_implicit = false;
static void parm_to_flagmap(const string&flag)
{
string key, value;
@@ -87,10 +80,13 @@ extern Design* elaborate(const map<string,Module*>&modules,
const string&root);
extern void cprop(Design*des);
extern void propinit(Design*des);
extern void sigfold(Design*des);
extern void synth(Design*des);
extern void syn_rules(Design*des);
extern void nobufz(Design*des);
extern void nodangle(Design*des);
extern void xnfio(Design*des);
extern void xnfsyn(Design*des);
typedef void (*net_func)(Design*);
static struct net_func_map {
@@ -98,10 +94,13 @@ static struct net_func_map {
void (*func)(Design*);
} func_table[] = {
{ "cprop", &cprop },
{ "nobufz", &nobufz },
{ "nodangle",&nodangle },
{ "propinit",&propinit },
{ "sigfold", &sigfold },
{ "synth", &synth },
{ "syn-rules", &syn_rules },
{ "xnfio", &xnfio },
{ "xnfsyn", &xnfsyn },
{ 0, 0 }
};
@@ -119,18 +118,13 @@ int main(int argc, char*argv[])
{
bool help_flag = false;
const char* net_path = 0;
const char* out_path = 0;
const char* pf_path = 0;
const char* warn_en = "";
int opt;
unsigned flag_errors = 0;
queue<net_func> net_func_queue;
flags["VPI_MODULE_LIST"] = "system";
flags["-o"] = "a.out";
min_typ_max_flag = TYP;
min_typ_max_warn = 10;
while ((opt = getopt(argc, argv, "F:f:hm:N:o:P:s:T:t:vW:")) != EOF) switch (opt) {
while ((opt = getopt(argc, argv, "F:f:hN:o:P:s:t:v")) != EOF) switch (opt) {
case 'F': {
net_func tmp = name_to_net_func(optarg);
if (tmp == 0) {
@@ -148,14 +142,11 @@ int main(int argc, char*argv[])
case 'h':
help_flag = true;
break;
case 'm':
flags["VPI_MODULE_LIST"] = flags["VPI_MODULE_LIST"]+","+optarg;
break;
case 'N':
net_path = optarg;
break;
case 'o':
flags["-o"] = optarg;
out_path = optarg;
break;
case 'P':
pf_path = optarg;
@@ -163,22 +154,6 @@ int main(int argc, char*argv[])
case 's':
start_module = optarg;
break;
case 'T':
if (strcmp(optarg,"min") == 0) {
min_typ_max_flag = MIN;
min_typ_max_warn = 0;
} else if (strcmp(optarg,"typ") == 0) {
min_typ_max_flag = TYP;
min_typ_max_warn = 0;
} else if (strcmp(optarg,"max") == 0) {
min_typ_max_flag = MAX;
min_typ_max_warn = 0;
} else {
cerr << "Invalid argument (" << optarg << ") to -T flag."
<< endl;
flag_errors += 1;
}
break;
case 't':
target = optarg;
break;
@@ -187,9 +162,6 @@ int main(int argc, char*argv[])
cout << COPYRIGHT << endl;
cout << endl << NOTICE << endl;
return 0;
case 'W':
warn_en = optarg;
break;
default:
flag_errors += 1;
break;
@@ -213,15 +185,6 @@ int main(int argc, char*argv[])
return 1;
}
/* Scan the warnings enable string for warning flags. */
for (const char*cp = warn_en ; *cp ; cp += 1) switch (*cp) {
case 'i':
warn_implicit = true;
break;
default:
break;
}
/* Parse the input. Make the pform. */
map<string,Module*> modules;
map<string,PUdp*> primitives;
@@ -295,9 +258,24 @@ int main(int argc, char*argv[])
}
bool emit_rc = emit(des, target);
bool emit_rc;
if (out_path) {
ofstream out;
out.open(out_path);
if (! out.is_open()) {
cerr << "Unable to open " << out_path << " for writing."
<< endl;
return 1;
}
emit_rc = emit(out, des, target);
} else {
emit_rc = emit(cout, des, target);
}
if (!emit_rc) {
cerr << "error: Code generation had errors." << endl;
cerr << "internal error: Code generation had errors." << endl;
return 1;
}
@@ -306,50 +284,6 @@ int main(int argc, char*argv[])
/*
* $Log: main.cc,v $
* Revision 1.38 2000/09/12 01:17:40 steve
* Version information for vlog_vpi_info.
*
* Revision 1.37 2000/08/09 03:43:45 steve
* Move all file manipulation out of target class.
*
* Revision 1.36 2000/07/29 17:58:21 steve
* Introduce min:typ:max support.
*
* Revision 1.35 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.34 2000/05/13 20:55:47 steve
* Use yacc based synthesizer.
*
* Revision 1.33 2000/05/08 05:29:43 steve
* no need for nobufz functor.
*
* Revision 1.32 2000/05/03 22:14:31 steve
* More features of ivl available through iverilog.
*
* Revision 1.31 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*
* Revision 1.30 2000/03/17 21:50:25 steve
* Switch to control warnings.
*
* Revision 1.29 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.28 2000/01/13 05:11:25 steve
* Support for multiple VPI modules.
*
* Revision 1.27 1999/12/30 17:37:14 steve
* Remove the now useless sigfold functor.
*
* Revision 1.26 1999/11/29 17:02:21 steve
* include getopt if present.
*
+2 -5
View File
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: mangle.cc,v 1.3 2000/02/23 02:56:54 steve Exp $"
#if !defined(WINNT)
#ident "$Id: mangle.cc,v 1.2 1999/02/15 05:52:50 steve Exp $"
#endif
# include "target.h"
@@ -63,9 +63,6 @@ string mangle(const string&str)
/*
* $Log: mangle.cc,v $
* Revision 1.3 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/02/15 05:52:50 steve
* Mangle that handles device instance numbers.
*
-46
View File
@@ -1,46 +0,0 @@
#ifndef __named_H
#define __named_H
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: named.h,v 1.2 2000/02/23 02:56:54 steve Exp $"
#endif
# include <string>
/*
* There are lots of places where names are attached to objects. This
* simple template expresses the lot.
*/
template <class T> struct named {
string name;
T parm;
};
/*
* $Log: named.h,v $
* Revision 1.2 2000/02/23 02:56:54 steve
* Macintosh compilers do not support ident.
*
* Revision 1.1 2000/01/09 05:50:49 steve
* Support named parameter override lists.
*
*/
#endif
-180
View File
@@ -1,180 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: net_assign.cc,v 1.5 2000/09/20 02:53:15 steve Exp $"
#endif
# include "netlist.h"
/*
* NetAssign
*/
unsigned count_lval_width(const NetAssign_*idx)
{
unsigned wid = 0;
while (idx) {
wid += idx->lwidth();
idx = idx->more;
}
return wid;
}
NetAssign_::NetAssign_(const string&n, unsigned w)
: NetNode(n, w), bmux_(0)
{
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
pin(idx).set_dir(Link::OUTPUT);
pin(idx).set_name("P", idx);
}
more = 0;
}
NetAssign_::~NetAssign_()
{
assert( more == 0 );
if (bmux_) delete bmux_;
}
void NetAssign_::set_bmux(NetExpr*r)
{
assert(bmux_ == 0);
bmux_ = r;
}
const NetExpr* NetAssign_::bmux() const
{
return bmux_;
}
unsigned NetAssign_::lwidth() const
{
if (bmux_) return 1;
else return pin_count();
}
NetAssignBase::NetAssignBase(NetAssign_*lv, NetExpr*rv)
: lval_(lv), rval_(rv)
{
}
NetAssignBase::~NetAssignBase()
{
if (rval_) delete rval_;
while (lval_) {
NetAssign_*tmp = lval_;
lval_ = tmp->more;
tmp->more = 0;
delete tmp;
}
}
NetExpr* NetAssignBase::rval()
{
return rval_;
}
const NetExpr* NetAssignBase::rval() const
{
return rval_;
}
void NetAssignBase::set_rval(NetExpr*r)
{
if (rval_) delete rval_;
rval_ = r;
}
NetAssign_* NetAssignBase::l_val(unsigned idx)
{
NetAssign_*cur = lval_;
while (idx > 0) {
if (cur == 0)
return cur;
cur = cur->more;
idx -= 1;
}
assert(idx == 0);
return cur;
}
const NetAssign_* NetAssignBase::l_val(unsigned idx) const
{
const NetAssign_*cur = lval_;
while (idx > 0) {
if (cur == 0)
return cur;
cur = cur->more;
idx -= 1;
}
assert(idx == 0);
return cur;
}
unsigned NetAssignBase::lwidth() const
{
unsigned sum = 0;
for (NetAssign_*cur = lval_ ; cur ; cur = cur->more)
sum += cur->lwidth();
return sum;
}
NetAssign::NetAssign(NetAssign_*lv, NetExpr*rv)
: NetAssignBase(lv, rv)
{
}
NetAssign::~NetAssign()
{
}
NetAssignNB::NetAssignNB(NetAssign_*lv, NetExpr*rv)
: NetAssignBase(lv, rv)
{
}
NetAssignNB::~NetAssignNB()
{
}
/*
* $Log: net_assign.cc,v $
* Revision 1.5 2000/09/20 02:53:15 steve
* Correctly measure comples l-values of assignments.
*
* Revision 1.4 2000/09/10 02:18:16 steve
* elaborate complex l-values
*
* Revision 1.3 2000/09/07 00:06:53 steve
* encapsulate access to the l-value expected width.
*
* Revision 1.2 2000/09/02 23:40:13 steve
* Pull NetAssign_ creation out of constructors.
*
* Revision 1.1 2000/09/02 20:54:20 steve
* Rearrange NetAssign to make NetAssign_ separate.
*
*/
-551
View File
@@ -1,551 +0,0 @@
/*
* Copyright (c) 2000Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: net_design.cc,v 1.16 2000/09/24 17:41:13 steve Exp $"
#endif
/*
* This source file contains all the implementations of the Design
* class declared in netlist.h.
*/
# include "netlist.h"
# include "util.h"
# include <strstream>
static string parse_last_name(string&path)
{
unsigned pos = path.rfind('.');
if (pos > path.length()) {
string res = path;
path = "";
return res;
}
string res = path.substr(pos+1, path.length());
path = path.substr(0, pos);
return res;
}
Design:: Design()
: errors(0), root_scope_(0), nodes_(0), procs_(0), lcounter_(0)
{
procs_idx_ = 0;
des_precision_ = 0;
}
Design::~Design()
{
}
string Design::local_symbol(const string&path)
{
strstream res;
res << "_L" << (lcounter_++) << ends;
return path + "." + res.str();
}
void Design::set_precision(int val)
{
if (val < des_precision_)
des_precision_ = val;
}
int Design::get_precision() const
{
return des_precision_;
}
unsigned long Design::scale_to_precision(unsigned long val,
const NetScope*scope) const
{
int units = scope->time_unit();
assert( units >= des_precision_ );
while (units > des_precision_) {
units -= 1;
val *= 10;
}
return val;
}
NetScope* Design::make_root_scope(const string&root)
{
assert(root_scope_ == 0);
root_scope_ = new NetScope(root);
return root_scope_;
}
NetScope* Design::find_root_scope()
{
assert(root_scope_);
return root_scope_;
}
const NetScope* Design::find_root_scope() const
{
assert(root_scope_);
return root_scope_;
}
/*
* This method locates a scope in the design, given its rooted
* heirarchical name. Each component of the key is used to scan one
* more step down the tree until the name runs out or the search
* fails.
*/
NetScope* Design::find_scope(const string&key) const
{
if (key == root_scope_->name())
return root_scope_;
string path = key;
string root = parse_first_name(path);
NetScope*cur = root_scope_;
if (root != cur->name())
return 0;
while (cur) {
string next = parse_first_name(path);
cur = cur->child(next);
if (path == "") return cur;
}
return cur;
}
/*
* This is a relative lookup of a scope by name. The starting point is
* the scope parameter is the place within which I start looking for
* the scope. If I do not find the scope within the passed scope,
* start looking in parent scopes until I find it, or I run out of
* parent scopes.
*/
NetScope* Design::find_scope(NetScope*scope, const string&name) const
{
assert(scope);
for ( ; scope ; scope = scope->parent()) {
string path = name;
string key = parse_first_name(path);
NetScope*cur = scope;
do {
cur = cur->child(key);
if (cur == 0) break;
key = parse_first_name(path);
} while (key != "");
if (cur) return cur;
}
// Last chance. Look for the name starting at the root.
return find_scope(name);
}
/*
* Find a parameter from within a specified context. If the name is
* not here, keep looking up until I run out of up to look at. The
* method works by scanning scopes, starting with the passed scope and
* working up towards the root, looking for the named parameter. The
* name in this case can be hierarchical, so there is an inner loop to
* follow the scopes of the name down to to key.
*/
const NetExpr* Design::find_parameter(const NetScope*scope,
const string&name) const
{
for ( ; scope ; scope = scope->parent()) {
string path = name;
string key = parse_first_name(path);
const NetScope*cur = scope;
while (path != "") {
cur = cur->child(key);
if (cur == 0) break;
key = parse_first_name(path);
}
if (cur == 0) continue;
if (const NetExpr*res = cur->get_parameter(key))
return res;
}
return 0;
}
/*
* This method runs through the scope, noticing the defparam
* statements that were collected during the elaborate_scope pass and
* applying them to the target parameters. The implementation actually
* works by using a specialized method from the NetScope class that
* does all the work for me.
*/
void Design::run_defparams()
{
root_scope_->run_defparams(this);
}
void NetScope::run_defparams(Design*des)
{
NetScope*cur = sub_;
while (cur) {
cur->run_defparams(des);
cur = cur->sib_;
}
map<string,NetExpr*>::const_iterator pp;
for (pp = defparams.begin() ; pp != defparams.end() ; pp ++ ) {
NetExpr*val = (*pp).second;
string path = (*pp).first;
string name = parse_last_name(path);
NetScope*targ_scope = des->find_scope(this, path);
if (targ_scope == 0) {
cerr << val->get_line() << ": warning: scope of " <<
path << "." << name << " not found." << endl;
continue;
}
val = targ_scope->set_parameter(name, val);
if (val == 0) {
cerr << val->get_line() << ": warning: parameter "
<< name << " not found in " << targ_scope->name()
<< "." << endl;
} else {
delete val;
}
}
}
void Design::evaluate_parameters()
{
root_scope_->evaluate_parameters(this);
}
void NetScope::evaluate_parameters(Design*des)
{
NetScope*cur = sub_;
while (cur) {
cur->evaluate_parameters(des);
cur = cur->sib_;
}
// Evaluate the parameter values. The parameter expressions
// have already been elaborated and replaced by the scope
// scanning code. Now the parameter expression can be fully
// evaluated, or it cannot be evaluated at all.
typedef map<string,NetExpr*>::iterator mparm_it_t;
for (mparm_it_t cur = parameters_.begin()
; cur != parameters_.end() ; cur ++) {
// Get the NetExpr for the parameter.
NetExpr*expr = (*cur).second;
assert(expr);
// If it's already a NetEConst, then this parameter is done.
if (dynamic_cast<const NetEConst*>(expr))
continue;
// Try to evaluate the expression.
NetExpr*nexpr = expr->eval_tree();
if (nexpr == 0) {
cerr << (*cur).second->get_line() << ": internal error: "
"unable to evaluate parm expression: " <<
*expr << endl;
des->errors += 1;
continue;
}
// The evaluate worked, replace the old expression with
// this constant value.
assert(nexpr);
delete expr;
(*cur).second = nexpr;
}
}
string Design::get_flag(const string&key) const
{
map<string,string>::const_iterator tmp = flags_.find(key);
if (tmp == flags_.end())
return "";
else
return (*tmp).second;
}
/*
* This method looks for a signal (reg, wire, whatever) starting at
* the specified scope. If the name is hierarchical, it is split into
* scope and name and the scope used to find the proper starting point
* for the real search.
*
* It is the job of this function to properly implement Verilog scope
* rules as signals are concerned.
*/
NetNet* Design::find_signal(NetScope*scope, const string&name)
{
assert(scope);
/* If the name has a path attached to it, parse it off and use
that to locate the desired starting scope. */
string path = name;
string key = parse_last_name(path);
if (path != "")
scope = find_scope(scope, path);
/* Now from the starting point, scan upwards until we find the
signal or we find a module boundary. */
while (scope) {
if (NetNet*net = scope->find_signal(key))
return net;
if (scope->type() == NetScope::MODULE)
break;
scope = scope->parent();
}
return 0;
}
NetMemory* Design::find_memory(NetScope*scope, const string&name)
{
assert(scope);
/* If the name has a path attached to it, parse it off and use
that to locate the desired scope. */
string path = name;
string key = parse_last_name(path);
if (path != "")
scope = find_scope(scope, path);
while (scope) {
if (NetMemory*mem = scope->find_memory(key))
return mem;
scope = scope->parent();
}
return 0;
}
void Design::find_symbol(NetScope*scope, const string&name,
NetNet*&sig, NetMemory*&mem)
{
sig = 0;
mem = 0;
/* If the name has a path attached to it, parse it off and use
that to locate the desired scope. Then locate the key
within that scope. */
string path = name;
string key = parse_last_name(path);
if (path != "")
scope = find_scope(scope, path);
/* If there is no path, then just search upwards for the key. */
while (scope) {
if (NetNet*cur = scope->find_signal(key)) {
sig = cur;
return;
}
if (NetMemory*cur = scope->find_memory(key)) {
mem = cur;
return;
}
scope = scope->parent();
}
}
NetFuncDef* Design::find_function(NetScope*scope, const string&name)
{
assert(scope);
NetScope*func = find_scope(scope, name);
if (func && (func->type() == NetScope::FUNC))
return func->func_def();
return 0;
}
NetFuncDef* Design::find_function(const string&key)
{
NetScope*func = find_scope(key);
if (func && (func->type() == NetScope::FUNC))
return func->func_def();
return 0;
}
NetTaskDef* Design::find_task(NetScope*scope, const string&name)
{
NetScope*task = find_scope(scope, name);
if (task && (task->type() == NetScope::TASK))
return task->task_def();
return 0;
}
NetTaskDef* Design::find_task(const string&key)
{
NetScope*task = find_scope(key);
if (task && (task->type() == NetScope::TASK))
return task->task_def();
return 0;
}
void Design::add_node(NetNode*net)
{
assert(net->design_ == 0);
if (nodes_ == 0) {
net->node_next_ = net;
net->node_prev_ = net;
} else {
net->node_next_ = nodes_->node_next_;
net->node_prev_ = nodes_;
net->node_next_->node_prev_ = net;
net->node_prev_->node_next_ = net;
}
nodes_ = net;
net->design_ = this;
}
void Design::del_node(NetNode*net)
{
assert(net->design_ == this);
if (nodes_ == net)
nodes_ = net->node_prev_;
if (nodes_ == net) {
nodes_ = 0;
} else {
net->node_next_->node_prev_ = net->node_prev_;
net->node_prev_->node_next_ = net->node_next_;
}
net->design_ = 0;
}
void Design::add_process(NetProcTop*pro)
{
pro->next_ = procs_;
procs_ = pro;
}
void Design::delete_process(NetProcTop*top)
{
assert(top);
if (procs_ == top) {
procs_ = top->next_;
} else {
NetProcTop*cur = procs_;
while (cur->next_ != top) {
assert(cur->next_);
cur = cur->next_;
}
cur->next_ = top->next_;
}
if (procs_idx_ == top)
procs_idx_ = top->next_;
delete top;
}
/*
* $Log: net_design.cc,v $
* Revision 1.16 2000/09/24 17:41:13 steve
* fix null pointer when elaborating undefined task.
*
* Revision 1.15 2000/08/26 00:54:03 steve
* Get at gate information for ivl_target interface.
*
* Revision 1.14 2000/08/12 17:59:48 steve
* Limit signal scope search at module boundaries.
*
* Revision 1.13 2000/07/30 18:25:43 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.12 2000/07/23 02:41:32 steve
* Excessive assert.
*
* Revision 1.11 2000/07/22 22:09:03 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.10 2000/07/16 04:56:08 steve
* Handle some edge cases during node scans.
*
* Revision 1.9 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.8 2000/05/02 16:27:38 steve
* Move signal elaboration to a seperate pass.
*
* Revision 1.7 2000/05/02 03:13:31 steve
* Move memories to the NetScope object.
*
* Revision 1.6 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.5 2000/04/28 16:50:53 steve
* Catch memory word parameters to tasks.
*
* Revision 1.4 2000/04/10 05:26:06 steve
* All events now use the NetEvent class.
*
* Revision 1.3 2000/03/11 03:25:52 steve
* Locate scopes in statements.
*
* Revision 1.2 2000/03/10 06:20:48 steve
* Handle defparam to partial hierarchical names.
*
* Revision 1.1 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
*/
-439
View File
@@ -1,439 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: net_event.cc,v 1.11 2000/10/04 16:30:39 steve Exp $"
#endif
# include "netlist.h"
NetEvent::NetEvent(const string&n)
: name_(0)
{
scope_ = 0;
snext_ = 0;
probes_ = 0;
trig_ = 0;
waitref_ = 0;
wlist_ = 0;
name_ = new char[n.length()+1];
strcpy(name_, n.c_str());
}
NetEvent::~NetEvent()
{
assert(waitref_ == 0);
if (scope_) scope_->rem_event(this);
while (probes_) {
NetEvProbe*tmp = probes_->enext_;
delete probes_;
probes_ = tmp;
}
delete[]name_;
}
const char* NetEvent::name() const
{
return name_;
}
string NetEvent::full_name() const
{
assert(scope_);
return scope_->name() + "." + name_;
}
unsigned NetEvent::nprobe() const
{
unsigned cnt = 0;
NetEvProbe*cur = probes_;
while (cur) {
cnt += 1;
cur = cur->enext_;
}
return cnt;
}
NetEvProbe* NetEvent::probe(unsigned idx)
{
NetEvProbe*cur = probes_;
while (cur && idx) {
cur = cur->enext_;
idx -= 1;
}
return cur;
}
unsigned NetEvent::ntrig() const
{
unsigned cnt = 0;
NetEvTrig*cur = trig_;
while (cur) {
cnt += 1;
cur = cur->enext_;
}
return cnt;
}
unsigned NetEvent::nwait() const
{
return waitref_;
}
NetEvent* NetEvent::find_similar_event()
{
if (probes_ == 0)
return 0;
#define NCAND 256
NetEvent*cand[NCAND];
bool cflg[NCAND];
unsigned ncand = 0;
NetEvProbe*cur = probes_;
/* First locate all the canditate events from the probe
objects that are connected to them and to my first
probe. All of these candidates have at least this probe in
common. */
for (NetNode*idx = cur->next_node()
; idx && (idx != cur) ; idx = idx->next_node()) {
NetEvProbe*tmp = dynamic_cast<NetEvProbe*>(idx);
if (tmp == 0)
continue;
if (tmp->edge() != cur->edge())
continue;
cand[ncand++] = tmp->event();
assert(ncand <= NCAND);
}
/* Now go through the remaining probes, checking that all the
candidate events also have a probe connected to this
one. By the time I finish this list, I will have eliminated
all the candidate events that are not connected to all of
my probes. */
for (cur = cur->enext_ ; cur && ncand ; cur = cur->enext_) {
for (unsigned idx = 0 ; idx < ncand ; idx += 1)
cflg[idx] = false;
/* For this probe, look for other probes connected to it
and find the event connected to it. Mark that event
as connected to this probe. */
for (NetNode*idx = cur->next_node()
; idx && (idx != cur) ; idx = idx->next_node()) {
NetEvProbe*tmp = dynamic_cast<NetEvProbe*>(idx);
if (tmp == 0)
continue;
if (tmp->edge() != cur->edge())
continue;
for (unsigned srch = 0 ; srch < ncand ; srch += 1)
if (cand[srch] == tmp->event()) {
cflg[srch] = true;
break;
}
}
/* Look for all the candidates that did not connect to
this probe (cflg is false) and eliminate them. */
for (unsigned idx = 0 ; idx < ncand ; ) {
if (cflg[idx]) {
idx += 1;
continue;
}
for (unsigned tmp = idx ; (tmp+1) < ncand ; tmp += 1) {
cflg[tmp] = cflg[tmp+1];
cand[tmp] = cand[tmp+1];
}
ncand -= 1;
}
}
/* Now, skip any of the remaining candidates for any that have
a different number of probes. These would be events that
have probes that I'm not connected to. */
for (unsigned idx = 0 ; idx < ncand ; idx += 1) {
if (cand[idx]->nprobe() == nprobe())
return cand[idx];
}
return 0;
}
void NetEvent::replace_event(NetEvent*that)
{
while (wlist_) {
wlist_->obj->replace_event(this, that);
}
}
NetEvTrig::NetEvTrig(NetEvent*ev)
: event_(ev)
{
enext_ = event_->trig_;
event_->trig_ = this;
}
NetEvTrig::~NetEvTrig()
{
if (event_->trig_ == this) {
event_->trig_ = enext_;
} else {
NetEvTrig*cur = event_->trig_;
while (cur->enext_ != this) {
assert(cur->enext_);
cur = cur->enext_;
}
cur->enext_ = this->enext_;
}
}
const NetEvent* NetEvTrig::event() const
{
return event_;
}
NetEvProbe::NetEvProbe(const string&n, NetEvent*tgt,
edge_t t, unsigned p)
: NetNode(n, p), event_(tgt), edge_(t)
{
for (unsigned idx = 0 ; idx < p ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name("P", idx);
}
enext_ = event_->probes_;
event_->probes_ = this;
}
NetEvProbe::~NetEvProbe()
{
if (event_->probes_ == this) {
event_->probes_ = enext_;
} else {
NetEvProbe*cur = event_->probes_;
while (cur->enext_ != this) {
assert(cur->enext_);
cur = cur->enext_;
}
cur->enext_ = this->enext_;
}
}
NetEvProbe::edge_t NetEvProbe::edge() const
{
return edge_;
}
NetEvent* NetEvProbe::event()
{
return event_;
}
const NetEvent* NetEvProbe::event() const
{
return event_;
}
NetEvWait::NetEvWait(NetProc*pr)
: statement_(pr), nevents_(0), events_(0)
{
}
NetEvWait::~NetEvWait()
{
if (events_) {
for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) {
NetEvent*tgt = events_[idx];
tgt->waitref_ -= 1;
struct NetEvent::wcell_*tmp = tgt->wlist_;
if (tmp->obj == this) {
tgt->wlist_ = tmp->next;
delete tmp;
} else {
assert(tmp->next);
while (tmp->next->obj != this) {
tmp = tmp->next;
assert(tmp->next);
}
tmp->next = tmp->next->next;
delete tmp;
}
}
delete[]events_;
}
delete statement_;
}
void NetEvWait::add_event(NetEvent*tgt)
{
assert(tgt);
if (nevents_ == 0) {
events_ = new NetEvent*[1];
} else {
NetEvent**tmp = new NetEvent*[nevents_+1];
for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) {
tmp[idx] = events_[idx];
assert(tmp[idx] != tgt);
}
delete[]events_;
events_ = tmp;
}
events_[nevents_] = tgt;
nevents_ += 1;
// Remember to tell the NetEvent that there is someone
// pointing to it.
tgt->waitref_ += 1;
struct NetEvent::wcell_*tmp = new NetEvent::wcell_;
tmp->obj = this;
tmp->next = tgt->wlist_;
tgt->wlist_ = tmp;
}
void NetEvWait::replace_event(NetEvent*src, NetEvent*repl)
{
unsigned idx;
for (idx = 0 ; idx < nevents_ ; idx += 1) {
if (events_[idx] == src)
break;
}
assert(idx < nevents_);
/* First, remove me from the list held by the src NetEvent. */
assert(src->waitref_ > 0);
src->waitref_ -= 1;
struct NetEvent::wcell_*tmp = src->wlist_;
if (tmp->obj == this) {
src->wlist_ = tmp->next;
delete tmp;
} else {
assert(tmp->next);
while (tmp->next->obj != this) {
tmp = tmp->next;
assert(tmp->next);
}
tmp->next = tmp->next->next;
delete tmp;
}
events_[idx] = repl;
// Remember to tell the replacement NetEvent that there is
// someone pointing to it.
repl->waitref_ += 1;
tmp = new NetEvent::wcell_;
tmp->obj = this;
tmp->next = repl->wlist_;
repl->wlist_ = tmp;
}
unsigned NetEvWait::nevents() const
{
return nevents_;
}
const NetEvent* NetEvWait::event(unsigned idx) const
{
assert(idx < nevents_);
return events_[idx];
}
NetEvent* NetEvWait::event(unsigned idx)
{
assert(idx < nevents_);
return events_[idx];
}
NetProc* NetEvWait::statement()
{
return statement_;
}
/*
* $Log: net_event.cc,v $
* Revision 1.11 2000/10/04 16:30:39 steve
* Use char8 instead of string to store name.
*
* Revision 1.10 2000/09/19 03:00:36 steve
* Typo stepping ot next probe in delete.
*
* Revision 1.9 2000/07/29 03:55:38 steve
* fix problem coalescing events w/ probes.
*
* Revision 1.8 2000/05/31 02:26:49 steve
* Globally merge redundant event objects.
*
* Revision 1.7 2000/05/27 19:33:23 steve
* Merge similar probes within a module.
*
* Revision 1.6 2000/04/18 04:50:20 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.5 2000/04/16 23:32:18 steve
* Synthesis of comparator in expressions.
*
* Connect the NetEvent and related classes
* together better.
*
* Revision 1.4 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*
* Revision 1.3 2000/04/12 04:23:58 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.2 2000/04/10 05:26:06 steve
* All events now use the NetEvent class.
*
* Revision 1.1 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
*/
-125
View File
@@ -1,125 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@picturel.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: net_force.cc,v 1.2 2000/05/12 01:22:41 steve Exp $"
#endif
/*
* This file contains implementatsion of the NetForce, NetRelease,
* NetCAssign and NetDeassign classes. These are similar or related in
* that they handle the procedural continuous assign and force
* statements.
*/
# include "netlist.h"
# include <assert.h>
/*
* Construct the procedural continuous assignment statement. This is a
* bit different from a normal assignment because the the lval is only
* intermittantly connected. The deassign in particular disconnects
* the signals when they are not being assigned anymore. Because of
* this, there is no other reference to the lval to make it stay put
* so we increment the eref.
*
* XXXX I'm not sure this is the right way. Perhaps I should create
* output pins to connect to the netlist? But that would cause the
* link ring to grow, and that is not quite correct either. Hmm...
*/
NetCAssign::NetCAssign(const string&n, NetNet*l)
: NetNode(n, l->pin_count()), lval_(l)
{
lval_->incr_eref();
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name("I", idx);
}
}
NetCAssign::~NetCAssign()
{
lval_->decr_eref();
}
const Link& NetCAssign::lval_pin(unsigned idx) const
{
assert(idx < lval_->pin_count());
return lval_->pin(idx);
}
NetDeassign::NetDeassign(NetNet*l)
: lval_(l)
{
lval_->incr_eref();
}
NetDeassign::~NetDeassign()
{
lval_->decr_eref();
}
const NetNet*NetDeassign::lval() const
{
return lval_;
}
NetForce::NetForce(const string&n, NetNet*l)
: NetNode(n, l->pin_count()), lval_(l)
{
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name("I", idx);
}
}
NetForce::~NetForce()
{
}
const Link& NetForce::lval_pin(unsigned idx) const
{
assert(idx < lval_->pin_count());
return lval_->pin(idx);
}
NetRelease::NetRelease(NetNet*l)
: lval_(l)
{
}
NetRelease::~NetRelease()
{
}
const NetNet*NetRelease::lval() const
{
return lval_;
}
/*
* $Log: net_force.cc,v $
* Revision 1.2 2000/05/12 01:22:41 steve
* NetCAssign needs to incr_eref its lval to lock it down.
*
* Revision 1.1 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
*
*/
-374
View File
@@ -1,374 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: net_link.cc,v 1.4 2000/10/06 23:46:50 steve Exp $"
#endif
# include "netlist.h"
# include <strstream>
# include <string>
# include <typeinfo>
void connect(Link&l, Link&r)
{
assert(&l != &r);
assert(l.nexus_);
assert(r.nexus_);
/* If the links are already connected, then we're done. */
if (l.nexus_ == r.nexus_)
return;
Nexus*tmp = r.nexus_;
while (Link*cur = tmp->first_nlink()) {
tmp->unlink(cur);
l.nexus_->relink(cur);
}
assert(tmp->list_ == 0);
assert(l.is_linked(r));
delete tmp;
}
Link::Link()
: dir_(PASSIVE), drive0_(STRONG), drive1_(STRONG), init_(verinum::Vx),
inst_(0), next_(0), nexus_(0)
{
(new Nexus()) -> relink(this);
}
Link::~Link()
{
assert(nexus_);
Nexus*tmp = nexus_;
nexus_->unlink(this);
if (tmp->list_ == 0)
delete tmp;
}
Nexus* Link::nexus()
{
return nexus_;
}
const Nexus* Link::nexus() const
{
return nexus_;
}
void Link::set_dir(DIR d)
{
dir_ = d;
}
Link::DIR Link::get_dir() const
{
return dir_;
}
void Link::drive0(Link::strength_t str)
{
drive0_ = str;
}
void Link::drive1(Link::strength_t str)
{
drive1_ = str;
}
Link::strength_t Link::drive0() const
{
return drive0_;
}
Link::strength_t Link::drive1() const
{
return drive1_;
}
void Link::set_init(verinum::V val)
{
init_ = val;
}
verinum::V Link::get_init() const
{
return init_;
}
void Link::cur_link(NetObj*&net, unsigned &pin)
{
net = node_;
pin = pin_;
}
void Link::cur_link(const NetObj*&net, unsigned &pin) const
{
net = node_;
pin = pin_;
}
void Link::unlink()
{
assert(nexus_);
if (! is_linked())
return;
nexus_->unlink(this);
(new Nexus()) -> relink(this);
}
bool Link::is_equal(const Link&that) const
{
return (node_ == that.node_) && (pin_ == that.pin_);
}
bool Link::is_linked() const
{
if (next_)
return true;
if (nexus_->first_nlink() != this)
return true;
return false;
}
bool Link::is_linked(const Link&that) const
{
return nexus_ == that.nexus_;
}
Link* Link::next_nlink()
{
return next_;
}
const Link* Link::next_nlink() const
{
return next_;
}
const NetObj*Link::get_obj() const
{
return node_;
}
NetObj*Link::get_obj()
{
return node_;
}
unsigned Link::get_pin() const
{
return pin_;
}
void Link::set_name(const string&n, unsigned i)
{
name_ = n;
inst_ = i;
}
const string& Link::get_name() const
{
return name_;
}
unsigned Link::get_inst() const
{
return inst_;
}
Nexus::Nexus()
{
name_ = 0;
list_ = 0;
t_cookie_ = 0;
}
Nexus::~Nexus()
{
assert(list_ == 0);
if (name_)
delete[]name_;
}
verinum::V Nexus::get_init() const
{
assert(list_);
for (Link*cur = list_ ; cur ; cur = cur->next_) {
if (cur->get_dir() == Link::OUTPUT)
return verinum::Vx;
if ((cur->get_dir() == Link::PASSIVE)
&& (cur->get_init() != verinum::Vz))
return cur->get_init();
}
return verinum::Vz;
}
void Nexus::unlink(Link*that)
{
if (name_) {
delete[] name_;
name_ = 0;
}
assert(that);
if (list_ == that) {
list_ = that->next_;
that->next_ = 0;
that->nexus_ = 0;
return;
}
Link*cur = list_;
while (cur->next_ != that) {
assert(cur->next_);
cur = cur->next_;
}
cur->next_ = that->next_;
that->nexus_ = 0;
that->next_ = 0;
}
void Nexus::relink(Link*that)
{
if (name_) {
delete[] name_;
name_ = 0;
}
assert(that->nexus_ == 0);
assert(that->next_ == 0);
that->next_ = list_;
that->nexus_ = this;
list_ = that;
}
Link* Nexus::first_nlink()
{
return list_;
}
const Link* Nexus::first_nlink() const
{
return list_;
}
void* Nexus::t_cookie() const
{
return t_cookie_;
}
void* Nexus::t_cookie(void*val)const
{
void*tmp = t_cookie_;
t_cookie_ = val;
return tmp;
}
const char* Nexus::name() const
{
if (name_)
return name_;
const NetNet*sig = 0;
unsigned pin = 0;
for (const Link*cur = first_nlink()
; cur ; cur = cur->next_nlink()) {
const NetNet*cursig = dynamic_cast<const NetNet*>(cur->get_obj());
if (cursig == 0)
continue;
if (sig == 0) {
sig = cursig;
pin = cur->get_pin();
continue;
}
if ((cursig->pin_count() == 1) && (sig->pin_count() > 1))
continue;
if ((cursig->pin_count() > 1) && (sig->pin_count() == 1)) {
sig = cursig;
pin = cur->get_pin();
continue;
}
if (cursig->local_flag() && !sig->local_flag())
continue;
if (cursig->name() < sig->name())
continue;
sig = cursig;
pin = cur->get_pin();
}
if (sig == 0) {
const Link*lnk = first_nlink();
const NetObj*obj = lnk->get_obj();
pin = lnk->get_pin();
cerr << "internal error: No signal for nexus of " <<
obj->name() << " pin " << pin << "(" <<
lnk->get_name() << "<" << lnk->get_inst() << ">)"
" type=" << typeid(*obj).name() << "?" << endl;
}
assert(sig);
ostrstream tmp;
tmp << sig->name();
if (sig->pin_count() > 1)
tmp << "<" << pin << ">";
tmp << ends;
name_ = new char[strlen(tmp.str()) + 1];
strcpy(name_, tmp.str());
return name_;
}
/*
* $Log: net_link.cc,v $
* Revision 1.4 2000/10/06 23:46:50 steve
* ivl_target updates, including more complete
* handling of ivl_nexus_t objects. Much reduced
* dependencies on pointers to netlist objects.
*
* Revision 1.3 2000/08/26 00:54:03 steve
* Get at gate information for ivl_target interface.
*
* Revision 1.2 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.1 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
*/
-105
View File
@@ -1,105 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: net_modulo.cc,v 1.1 2000/09/17 21:26:15 steve Exp $"
#endif
# include <typeinfo>
# include <iostream>
# include <iomanip>
# include <cassert>
# include "netlist.h"
NetModulo::NetModulo(const string&n, unsigned wr,
unsigned wa, unsigned wb)
: NetNode(n, wr+wa+wb), width_r_(wr), width_a_(wa), width_b_(wb)
{
unsigned p = 0;
for (unsigned idx = 0 ; idx < width_r_ ; idx += 1, p += 1) {
pin(p).set_dir(Link::OUTPUT);
pin(p).set_name("Result", idx);
}
for (unsigned idx = 0 ; idx < width_a_ ; idx += 1, p += 1) {
pin(p).set_dir(Link::INPUT);
pin(p).set_name("DataA", idx);
}
for (unsigned idx = 0 ; idx < width_b_ ; idx += 1, p += 1) {
pin(p).set_dir(Link::INPUT);
pin(p).set_name("DataB", idx);
}
}
NetModulo::~NetModulo()
{
}
unsigned NetModulo::width_r() const
{
return width_r_;
}
unsigned NetModulo::width_a() const
{
return width_a_;
}
unsigned NetModulo::width_b() const
{
return width_b_;
}
Link& NetModulo::pin_Result(unsigned idx)
{
assert(idx < width_r_);
return pin(idx);
}
const Link& NetModulo::pin_Result(unsigned idx) const
{
assert(idx < width_r_);
return pin(idx);
}
Link& NetModulo::pin_DataA(unsigned idx)
{
assert(idx < width_a_);
return pin(idx+width_r_);
}
const Link& NetModulo::pin_DataA(unsigned idx) const
{
assert(idx < width_a_);
return pin(idx+width_r_);
}
Link& NetModulo::pin_DataB(unsigned idx)
{
assert(idx < width_b_);
return pin(idx+width_r_+width_a_);
}
const Link& NetModulo::pin_DataB(unsigned idx) const
{
assert(idx < width_b_);
return pin(idx+width_r_+width_a_);
}
-105
View File
@@ -1,105 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: net_proc.cc,v 1.2 2000/07/27 05:13:44 steve Exp $"
#endif
# include "netlist.h"
# include <assert.h>
NetDisable::NetDisable(NetScope*tgt)
: target_(tgt)
{
}
NetDisable::~NetDisable()
{
}
const NetScope* NetDisable::target() const
{
return target_;
}
NetForever::NetForever(NetProc*p)
: statement_(p)
{
}
NetForever::~NetForever()
{
delete statement_;
}
NetPDelay::NetPDelay(unsigned long d, NetProc*st)
: delay_(d), expr_(0), statement_(st)
{
}
NetPDelay::NetPDelay(NetExpr*d, NetProc*st)
: delay_(0), expr_(d), statement_(st)
{
}
NetPDelay::~NetPDelay()
{
if (expr_) delete expr_;
}
unsigned long NetPDelay::delay() const
{
assert(expr_ == 0);
return delay_;
}
const NetExpr* NetPDelay::expr() const
{
return expr_;
}
NetRepeat::NetRepeat(NetExpr*e, NetProc*p)
: expr_(e), statement_(p)
{
}
NetRepeat::~NetRepeat()
{
delete expr_;
delete statement_;
}
const NetExpr* NetRepeat::expr() const
{
return expr_;
}
/*
* $Log: net_proc.cc,v $
* Revision 1.2 2000/07/27 05:13:44 steve
* Support elaboration of disable statements.
*
* Revision 1.1 2000/07/07 04:53:54 steve
* Add support for non-constant delays in delay statements,
* Support evaluating ! in constant expressions, and
* move some code from netlist.cc to net_proc.cc.
*
*/
-398
View File
@@ -1,398 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: net_scope.cc,v 1.10 2000/10/06 23:46:50 steve Exp $"
#endif
# include "netlist.h"
# include <strstream>
/*
* The NetScope class keeps a scope tree organized. Each node of the
* scope tree points to its parent, its right sibling and its leftmost
* child. The root node has no parent or siblings. The node stores the
* name of the scope. The complete hierarchical name of the scope is
* formed by appending the path of scopes from the root to the scope
* in question.
*/
NetScope::NetScope(const string&n)
: type_(NetScope::MODULE), up_(0), sib_(0), sub_(0)
{
memories_ = 0;
signals_ = 0;
events_ = 0;
lcounter_ = 0;
name_ = new char[n.length()+1];
strcpy(name_, n.c_str());
}
NetScope::NetScope(NetScope*up, const string&n, NetScope::TYPE t)
: type_(t), up_(up), sib_(0), sub_(0)
{
memories_ = 0;
signals_ = 0;
events_ = 0;
time_unit_ = up->time_unit();
time_prec_ = up->time_precision();
sib_ = up_->sub_;
up_->sub_ = this;
switch (t) {
case NetScope::TASK:
task_ = 0;
break;
case NetScope::FUNC:
func_ = 0;
break;
}
name_ = new char[n.length()+1];
strcpy(name_, n.c_str());
}
NetScope::~NetScope()
{
assert(sib_ == 0);
assert(sub_ == 0);
lcounter_ = 0;
delete[]name_;
}
NetExpr* NetScope::set_parameter(const string&key, NetExpr*expr)
{
NetExpr*&ref = parameters_[key];
NetExpr* res = ref;
ref = expr;
return res;
}
NetExpr* NetScope::set_localparam(const string&key, NetExpr*expr)
{
NetExpr*&ref = localparams_[key];
NetExpr* res = ref;
ref = expr;
return res;
}
const NetExpr* NetScope::get_parameter(const string&key) const
{
map<string,NetExpr*>::const_iterator idx;
idx = parameters_.find(key);
if (idx != parameters_.end())
return (*idx).second;
idx = localparams_.find(key);
if (idx != localparams_.end())
return (*idx).second;
return 0;
}
NetScope::TYPE NetScope::type() const
{
return type_;
}
void NetScope::set_task_def(NetTaskDef*def)
{
assert( type_ == TASK );
assert( task_ == 0 );
task_ = def;
}
NetTaskDef* NetScope::task_def()
{
assert( type_ == TASK );
return task_;
}
const NetTaskDef* NetScope::task_def() const
{
assert( type_ == TASK );
return task_;
}
void NetScope::set_func_def(NetFuncDef*def)
{
assert( type_ == FUNC );
assert( func_ == 0 );
func_ = def;
}
NetFuncDef* NetScope::func_def()
{
assert( type_ == FUNC );
return func_;
}
const NetFuncDef* NetScope::func_def() const
{
assert( type_ == FUNC );
return func_;
}
void NetScope::time_unit(int val)
{
time_unit_ = val;
}
void NetScope::time_precision(int val)
{
time_prec_ = val;
}
int NetScope::time_unit() const
{
return time_unit_;
}
int NetScope::time_precision() const
{
return time_prec_;
}
const char* NetScope::basename() const
{
return name_;
}
string NetScope::name() const
{
if (up_)
return up_->name() + "." + name_;
else
return name_;
}
void NetScope::add_event(NetEvent*ev)
{
assert(ev->scope_ == 0);
ev->scope_ = this;
ev->snext_ = events_;
events_ = ev;
}
void NetScope::rem_event(NetEvent*ev)
{
assert(ev->scope_ == this);
ev->scope_ = 0;
if (events_ == ev) {
events_ = ev->snext_;
} else {
NetEvent*cur = events_;
while (cur->snext_ != ev) {
assert(cur->snext_);
cur = cur->snext_;
}
cur->snext_ = ev->snext_;
}
ev->snext_ = 0;
}
NetEvent* NetScope::find_event(const string&name)
{
for (NetEvent*cur = events_; cur ; cur = cur->snext_)
if (cur->name() == name)
return cur;
return 0;
}
void NetScope::add_signal(NetNet*net)
{
if (signals_ == 0) {
net->sig_next_ = net;
net->sig_prev_ = net;
} else {
net->sig_next_ = signals_->sig_next_;
net->sig_prev_ = signals_;
net->sig_next_->sig_prev_ = net;
net->sig_prev_->sig_next_ = net;
}
signals_ = net;
}
void NetScope::rem_signal(NetNet*net)
{
assert(net->scope() == this);
if (signals_ == net)
signals_ = net->sig_prev_;
if (signals_ == net) {
signals_ = 0;
} else {
net->sig_prev_->sig_next_ = net->sig_next_;
net->sig_next_->sig_prev_ = net->sig_prev_;
}
}
NetNet* NetScope::find_signal(const string&key)
{
if (signals_ == 0)
return 0;
string fulname = name()+"."+key;
NetNet*cur = signals_;
do {
if (cur->name() == fulname)
return cur;
cur = cur->sig_prev_;
} while (cur != signals_);
return 0;
}
void NetScope::add_memory(NetMemory*mem)
{
if (memories_ == 0) {
mem->snext_ = mem;
mem->sprev_ = mem;
} else {
mem->snext_ = memories_->snext_;
mem->sprev_ = memories_;
mem->snext_->sprev_ = mem;
mem->sprev_->snext_ = mem;
}
memories_ = mem;
mem->scope_ = this;
}
void NetScope::rem_memory(NetMemory*mem)
{
assert(mem->scope_ == this);
if (memories_ == mem)
memories_ = mem->sprev_;
if (memories_ == mem) {
memories_ = 0;
} else {
mem->sprev_->snext_ = mem->snext_;
mem->snext_->sprev_ = mem->sprev_;
}
mem->scope_ = 0;
}
NetMemory* NetScope::find_memory(const string&key)
{
if (memories_ == 0)
return 0;
string fulname = name()+"."+key;
NetMemory*cur = memories_;
do {
if (cur->name() == fulname)
return cur;
cur = cur->sprev_;
} while (cur != memories_);
return 0;
}
/*
* This method locates a child scope by name. The name is the simple
* name of the child, no heirarchy is searched.
*/
NetScope* NetScope::child(const string&name)
{
if (sub_ == 0) return 0;
NetScope*cur = sub_;
while (cur->name_ != name) {
if (cur->sib_ == 0) return 0;
cur = cur->sib_;
}
return cur;
}
const NetScope* NetScope::child(const string&name) const
{
if (sub_ == 0) return 0;
NetScope*cur = sub_;
while (cur->name_ != name) {
if (cur->sib_ == 0) return 0;
cur = cur->sib_;
}
return cur;
}
NetScope* NetScope::parent()
{
return up_;
}
const NetScope* NetScope::parent() const
{
return up_;
}
string NetScope::local_symbol()
{
strstream res;
res << "_l" << (lcounter_++) << ends;
return res.str();
}
/*
* $Log: net_scope.cc,v $
* Revision 1.10 2000/10/06 23:46:50 steve
* ivl_target updates, including more complete
* handling of ivl_nexus_t objects. Much reduced
* dependencies on pointers to netlist objects.
*
* Revision 1.9 2000/08/27 15:51:50 steve
* t-dll iterates signals, and passes them to the
* target module.
*
* Some of NetObj should return char*, not string.
*
* Revision 1.8 2000/07/30 18:25:44 steve
* Rearrange task and function elaboration so that the
* NetTaskDef and NetFuncDef functions are created during
* signal enaboration, and carry these objects in the
* NetScope class instead of the extra, useless map in
* the Design class.
*
* Revision 1.7 2000/07/22 22:09:03 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.6 2000/05/02 03:13:31 steve
* Move memories to the NetScope object.
*
* Revision 1.5 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.4 2000/04/18 04:50:20 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.3 2000/04/10 05:26:06 steve
* All events now use the NetEvent class.
*
* Revision 1.2 2000/04/09 17:04:56 steve
* uninitialized event_ list.
*
* Revision 1.1 2000/04/04 03:20:15 steve
* Simulate named event trigger and waits.
*
*/
-205
View File
@@ -1,205 +0,0 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: net_udp.cc,v 1.1 2000/03/29 04:37:11 steve Exp $"
#endif
# include "netlist.h"
NetUDP::NetUDP(const string&n, unsigned pins, bool sequ)
: NetNode(n, pins), sequential_(sequ), init_('x')
{
pin(0).set_dir(Link::OUTPUT);
for (unsigned idx = 1 ; idx < pins ; idx += 1)
pin(idx).set_dir(Link::INPUT);
}
bool NetUDP::set_table(const string&input, char output)
{
assert((output == '0') || (output == '1') || (sequential_ &&
(output == '-')));
if (sequential_) {
assert(input.length() == pin_count());
/* XXXX Need to check to make sure that the input vector
contains a legal combination of characters. */
return sequ_glob_(input, output);
} else {
assert(input.length() == (pin_count()-1));
/* XXXX Need to check to make sure that the input vector
contains a legal combination of characters. In
combinational UDPs, only 0, 1 and x are allowed. */
cm_[input] = output;
return true;
}
}
void NetUDP::cleanup_table()
{
for (FSM_::iterator idx = fsm_.begin() ; idx != fsm_.end() ; idx++) {
string str = (*idx).first;
state_t_*st = (*idx).second;
assert(str[0] == st->out);
for (unsigned pin = 0 ; pin < pin_count() ; pin += 1) {
if (st->pins[pin].zer && st->pins[pin].zer->out == 'x')
st->pins[pin].zer = 0;
if (st->pins[pin].one && st->pins[pin].one->out == 'x')
st->pins[pin].one = 0;
if (st->pins[pin].xxx && st->pins[pin].xxx->out == 'x')
st->pins[pin].xxx = 0;
}
}
for (FSM_::iterator idx = fsm_.begin() ; idx != fsm_.end() ; ) {
FSM_::iterator cur = idx;
idx ++;
state_t_*st = (*cur).second;
if (st->out != 'x')
continue;
for (unsigned pin = 0 ; pin < pin_count() ; pin += 1) {
if (st->pins[pin].zer)
goto break_label;
if (st->pins[pin].one)
goto break_label;
if (st->pins[pin].xxx)
goto break_label;
}
//delete st;
fsm_.erase(cur);
break_label:;
}
}
char NetUDP::table_lookup(const string&from, char to, unsigned pin) const
{
assert(pin <= pin_count());
assert(from.length() == pin_count());
FSM_::const_iterator idx = fsm_.find(from);
if (idx == fsm_.end())
return 'x';
state_t_*next;
switch (to) {
case '0':
next = (*idx).second->pins[pin].zer;
break;
case '1':
next = (*idx).second->pins[pin].one;
break;
case 'x':
next = (*idx).second->pins[pin].xxx;
break;
default:
assert(0);
next = 0;
}
return next? next->out : 'x';
}
void NetUDP::set_initial(char val)
{
assert(sequential_);
assert((val == '0') || (val == '1') || (val == 'x'));
init_ = val;
}
NetUDP::state_t_* NetUDP::find_state_(const string&str)
{
map<string,state_t_*>::iterator cur = fsm_.find(str);
if (cur != fsm_.end())
return (*cur).second;
state_t_*st = fsm_[str];
if (st == 0) {
st = new state_t_(pin_count());
st->out = str[0];
fsm_[str] = st;
}
return st;
}
NetUDP_COMB::NetUDP_COMB(const string&n, unsigned pins)
: NetNode(n, pins)
{
pin(0).set_dir(Link::OUTPUT);
pin(0).set_name("O", 0);
for (unsigned idx = 1 ; idx < pins ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name("I", idx-1);
}
}
void NetUDP_COMB::set_table(const string&input, char output)
{
assert((output == '0') || (output == '1'));
assert(input.length() == (pin_count()-1));
/* XXXX Need to check to make sure that the input vector
contains a legal combination of characters. In
combinational UDPs, only 0, 1 and x are allowed. */
cm_[input] = output;
}
void NetUDP_COMB::cleanup_table()
{
}
bool NetUDP_COMB::first(string&inp, char&out) const
{
idx_ = cm_.begin();
if (idx_ == cm_.end())
return false;
inp = (*idx_).first;
out = (*idx_).second;
return true;
}
bool NetUDP_COMB::next(string&inp, char&out) const
{
idx_ ++;
if (idx_ == cm_.end())
return false;
inp = (*idx_).first;
out = (*idx_).second;
return true;
}
/*
* $Log: net_udp.cc,v $
* Revision 1.1 2000/03/29 04:37:11 steve
* New and improved combinational primitives.
*
*/
+1274 -851
View File
File diff suppressed because it is too large Load Diff
+683 -1238
View File
File diff suppressed because it is too large Load Diff
+6 -77
View File
@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ident "$Id: netlist.txt,v 1.10 2000/07/23 18:06:15 steve Exp $"
#ident "$Id: netlist.txt,v 1.7 1999/11/28 23:42:02 steve Exp $"
Note that the netlist.h header contains detailed descriptions of how
@@ -60,20 +60,13 @@ changed during processing.
STRUCTURAL LINKS
The NetNode and NetNet classes contain arrays of Link objects, one
object per pin. Each pin is a single bit. The Link objects link to all
the NetNode and NetNet objects' links that are connected together in
the design, and to a Nexus object. This way, code that examines a node
object per pin. Each pin is a single bit. The Link objects link
circularly to all the NetNode and NetNet objects' links that are
connected together in the design. This way, code that examines a node
of the design can discover what is connected to each pin.
The connected set of links also has common properties that are stored
or access from the Nexus object. All the Links that are connected
together are also connected to a single Nexus object. This object is
useful for accessing the properties and values that come from the
connected set of links. The Nexus object is also handy for iterating
over the connected set of Links.
See the Link class definition in netlist.h for a description of the link
methods, and the Nexus class for nexus global methods.
See the NetObj::Link class definition for a description of the link
methods.
Currently, a link has 3 possible direction properties:
@@ -236,29 +229,6 @@ can operate globally, with optimizations freely crossing module
boundaries. This makes coding of netlist transform functions such as
constant propagation more effective and easier to write.
SCOPE REPRESENTATION IN NETLISTS
In spite of the literal flattening of the design, scope information is
preserved in the netlist, with the NetScope class. The Design class
keeps a single pointer to the root scope of the design. This is the
scope of the root module. Scopes that are then created within that
(or any nested) module are placed as children of the root scope, and
those children can have further children, and so on.
Each scope in the tree carries its own name, and its relationship to
its parent and children. This makes it possible to walk the tree of
scopes. In practice, the walking of the scopes is handled by recursive
methods.
Each scope also carries the parameters that are applicable to the
scope itself. The parameter expression (possibly evaluated) can be
located by name, given the scope object itself. The scan of the pform
to generate scopes also places the parameters that are declared in the
scope. Overrides are managed during the scan, and once the scan is
complete, defparam overrides are applied.
TASKS IN NETLISTS
The flattening of the design does not include tasks and named
@@ -269,48 +239,7 @@ recurse. (The elaboration process does reserve the right to flatten
some task calls. C++ programmers recognize this as inlining a task.)
TIME SCALE IN NETLISTS
The Design class and the NetScope classes carry time scale and
resolution information of the elaborated design. There is a global
resolution, and there are scope specific units and resolutions. Units
and resolutions are specified as signed integers, and interpreted as
the power of 10 of the value. For example, a resolution "-9" means
that "1" is 1ns (1e-9). The notation supports units from -128 to +127.
It is up to the back-ends to interpret "-4" as "100us".
Delays are expressed in the netlist by integers. The units of these
delays are always given in the units of the design precision. This
allows everything to work with integers, and generally places the
burden of scaling delays into elaboration. This is, after all, a
common task. The Design::get_precision() method gets the global design
precision.
Each NetScope also carries its local time_units and time_precision
values. These are filled in during scope elaboration and are used in
subsequent elaboration phases to arrange for scaling of delays. This
information can also be used by the code generator to scale times back
to the units of the scope, if that is desired.
$Log: netlist.txt,v $
Revision 1.10 2000/07/23 18:06:15 steve
Document time scale in netlists.
Revision 1.9 2000/07/14 06:12:57 steve
Move inital value handling from NetNet to Nexus
objects. This allows better propogation of inital
values.
Clean up constant propagation a bit to account
for regs that are not really values.
Revision 1.8 2000/03/08 04:36:54 steve
Redesign the implementation of scopes and parameters.
I now generate the scopes and notice the parameters
in a separate pass over the pform. Once the scopes
are generated, I can process overrides and evalutate
paremeters before elaboration begins.
Revision 1.7 1999/11/28 23:42:02 steve
NetESignal object no longer need to be NetNode
objects. Let them keep a pointer to NetNet objects.
+3 -66
View File
@@ -1,7 +1,7 @@
#ifndef __netmisc_H
#define __netmisc_H
/*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: netmisc.h,v 1.9 2000/09/20 02:53:15 steve Exp $"
#if !defined(WINNT)
#ident "$Id: netmisc.h,v 1.1 1999/09/29 00:42:51 steve Exp $"
#endif
# include "netlist.h"
@@ -31,73 +31,10 @@
* enough.
*/
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid);
extern NetNet*pad_to_width(Design*des, const string&p, NetNet*n, unsigned w);
/*
* Check to see if the link has a constant value driven to it. If
* there is only a NetConst driving this pin, the return a pointer to
* that NetConst object. Also, return the index of the bit in that
* constant through the idx parameter.
*/
extern NetConst* link_const_value(Link&pin, unsigned&idx);
/*
* This local function returns true if all the the possible drivers of
* this link are constant. It will also return true if there are no
* drivers at all.
*/
extern bool link_drivers_constant(const Link&lnk);
/*
* This function returns the value of the constant driving this link,
* or Vz if there is no constant. The results of this function are
* only meaningful if link_drivers_constant(lnk) == true.
*/
extern verinum::V driven_value(const Link&lnk);
/*
* In some cases the lval is accessible as a pointer to the head of
* a list of NetAssign_ objects. This function returns the width of
* the l-value represented by this list.
*/
extern unsigned count_lval_width(const class NetAssign_*first);
/*
* $Log: netmisc.h,v $
* Revision 1.9 2000/09/20 02:53:15 steve
* Correctly measure comples l-values of assignments.
*
* Revision 1.8 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
* Revision 1.7 2000/05/14 17:55:04 steve
* Support initialization of FF Q value.
*
* Revision 1.6 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.5 2000/04/20 00:28:03 steve
* Catch some simple identity compareoptimizations.
*
* Revision 1.4 2000/03/16 19:03:03 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.3 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 2000/02/16 03:58:27 steve
* Fix up width matching in structural bitwise operators.
*
* Revision 1.1 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@picturel.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* 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: nobufz.cc,v 1.1 1998/12/02 04:37:13 steve Exp $"
#endif
/* NOBUFZ Function
* This function transforms the netlist by removing BUFZ nodes that
* have no obvious effect. The assumption here is that the BUFZ node
* transmits information perfectly in one direction, and not at all in
* the other.
*
* A BUFZ will *not* be eliminated if the output link is connected to
* other outputs. The BUFZ protects its input link from the
* double-driving on its output, so the bufz is not meaningless and
* cannot be removed.
*/
# include "netlist.h"
# include <assert.h>
static bool is_a_bufz_node(const NetNode*obj)
{
return dynamic_cast<const NetBUFZ*>(obj);
}
void nobufz(Design*des)
{
des->clear_node_marks();
while (NetNode*obj = des->find_node(&is_a_bufz_node)) {
NetBUFZ*cur = dynamic_cast<NetBUFZ*>(obj);
assert(cur);
/* If there are more output pins on the output size of
the BUFZ, then the BUFZ has a real effect (it
protects its input side) and cannot be eliminated. */
if (count_outputs(cur->pin(0)) == 1) {
connect(cur->pin(0), cur->pin(1));
delete cur;
} else {
cur->set_mark();
}
}
}
/*
* $Log: nobufz.cc,v $
* Revision 1.1 1998/12/02 04:37:13 steve
* Add the nobufz function to eliminate bufz objects,
* Object links are marked with direction,
* constant propagation is more careful will wide links,
* Signal folding is aware of attributes, and
* the XNF target can dump UDP objects based on LCA
* attributes.
*
*/
+6 -62
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: nodangle.cc,v 1.8 2000/06/25 19:59:42 steve Exp $"
#if !defined(WINNT)
#ident "$Id: nodangle.cc,v 1.2 1999/11/28 23:42:02 steve Exp $"
#endif
/*
@@ -31,24 +31,9 @@
class nodangle_f : public functor_t {
public:
void event(Design*des, NetEvent*ev);
void signal(Design*des, NetNet*sig);
};
void nodangle_f::event(Design*des, NetEvent*ev)
{
if (NetEvent*match = ev->find_similar_event()) {
ev->replace_event(match);
}
if (ev->nwait() != 0)
return;
if (ev->ntrig() != 0)
return;
delete ev;
}
void nodangle_f::signal(Design*des, NetNet*sig)
{
@@ -57,35 +42,18 @@ void nodangle_f::signal(Design*des, NetNet*sig)
if (sig->get_eref() > 0)
return;
/* Look for a completely unconnected signal. */
unsigned unlinked = 0;
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1)
if (! sig->pin(idx).is_linked()) unlinked += 1;
if (unlinked == sig->pin_count()) {
delete sig;
return;
}
/* Check to see if there is some significant signal connected
to every pin of this signal. */
unsigned significant_flags = 0;
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) {
Nexus*nex = sig->pin(idx).nexus();
for (Link*cur = nex->first_nlink()
; cur ; cur = cur->next_nlink()) {
if (cur == &sig->pin(idx))
continue;
NetObj::Link&lnk = sig->pin(idx);
for (NetObj::Link*cur = lnk.next_link()
; cur != &lnk ; cur = cur->next_link()) {
NetNet*cursig = dynamic_cast<NetNet*>(cur->get_obj());
if (cursig == 0)
continue;
if (cursig->local_flag())
continue;
significant_flags += 1;
break;
}
@@ -105,30 +73,6 @@ void nodangle(Design*des)
/*
* $Log: nodangle.cc,v $
* Revision 1.8 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
* Revision 1.7 2000/05/31 02:26:49 steve
* Globally merge redundant event objects.
*
* Revision 1.6 2000/05/07 04:37:56 steve
* Carry strength values from Verilog source to the
* pform and netlist for gates.
*
* Change vvm constants to use the driver_t to drive
* a constant value. This works better if there are
* multiple drivers on a signal.
*
* Revision 1.5 2000/04/28 21:00:29 steve
* Over agressive signal elimination in constant probadation.
*
* Revision 1.4 2000/04/18 04:50:20 steve
* Clean up unneeded NetEvent objects.
*
* Revision 1.3 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.2 1999/11/28 23:42:02 steve
* NetESignal object no longer need to be NetNode
* objects. Let them keep a pointer to NetNet objects.
+3 -40
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: pad_to_width.cc,v 1.5 2000/05/02 00:58:12 steve Exp $"
#if !defined(WINNT)
#ident "$Id: pad_to_width.cc,v 1.1 1999/09/29 00:42:51 steve Exp $"
#endif
# include "netlist.h"
@@ -34,9 +34,7 @@ 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);
co->set_line(*expr);
NetEConcat*cc = new NetEConcat(2);
cc->set_line(*expr);
cc->set(0, co);
cc->set(1, expr);
cc->set_width(wid);
@@ -45,44 +43,9 @@ NetExpr*pad_to_width(NetExpr*expr, unsigned wid)
return expr;
}
NetNet*pad_to_width(Design*des, const string&path, NetNet*net, unsigned wid)
{
NetScope*scope = des->find_scope(path);
assert(scope);
if (net->pin_count() >= wid)
return net;
verinum pad(verinum::V0, wid - net->pin_count());
NetConst*con = new NetConst(des->local_symbol(path), pad);
des->add_node(con);
NetNet*tmp = new NetNet(scope, des->local_symbol(path),
NetNet::WIRE, wid);
tmp->local_flag(true);
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1)
connect(tmp->pin(idx), net->pin(idx));
for (unsigned idx = net->pin_count() ; idx < wid ; idx += 1)
connect(tmp->pin(idx), con->pin(idx-net->pin_count()));
return tmp;
}
/*
* $Log: pad_to_width.cc,v $
* Revision 1.5 2000/05/02 00:58:12 steve
* Move signal tables to the NetScope class.
*
* Revision 1.4 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 2000/02/16 03:58:27 steve
* Fix up width matching in structural bitwise operators.
*
* Revision 1.2 2000/01/01 06:17:25 steve
* Propogate line number information when expanding expressions.
*
* Revision 1.1 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
+161 -549
View File
File diff suppressed because it is too large Load Diff
+3 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: parse_misc.cc,v 1.4 2000/02/23 02:56:55 steve Exp $"
#if !defined(WINNT)
#ident "$Id: parse_misc.cc,v 1.3 1999/09/29 21:15:31 steve Exp $"
#endif
# include "parse_misc.h"
@@ -58,9 +58,6 @@ int VLwrap()
/*
* $Log: parse_misc.cc,v $
* Revision 1.4 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/09/29 21:15:31 steve
* Standardize formatting of warning messages.
*
+3 -6
View File
@@ -1,7 +1,7 @@
#ifndef __parse_misc_H
#define __parse_misc_H
/*
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: parse_misc.h,v 1.4 2000/02/23 02:56:55 steve Exp $"
#if !defined(WINNT)
#ident "$Id: parse_misc.h,v 1.3 1999/07/10 01:03:18 steve Exp $"
#endif
# include <list>
@@ -53,9 +53,6 @@ extern unsigned error_count, warn_count;
/*
* $Log: parse_misc.h,v $
* Revision 1.4 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.3 1999/07/10 01:03:18 steve
* remove string from lexical phase.
*
+175 -297
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2000 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
@@ -16,14 +16,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: pform.cc,v 1.64 2000/09/13 16:32:26 steve Exp $"
#if !defined(WINNT)
#ident "$Id: pform.cc,v 1.47 1999/11/23 01:04:57 steve Exp $"
#endif
# include "compiler.h"
# include "pform.h"
# include "parse_misc.h"
# include "PEvent.h"
# include "PUdp.h"
# include <list>
# include <map>
@@ -39,8 +38,6 @@ string vl_file = "";
extern int VLparse();
static Module*pform_cur_module = 0;
static int pform_time_unit = 0;
static int pform_time_prec = 0;
/*
* The scope stack and the following functions handle the processing
@@ -55,13 +52,6 @@ struct scope_name_t {
};
static scope_name_t*scope_stack = 0;
void pform_set_timescale(int unit, int prec)
{
assert(unit >= prec);
pform_time_unit = unit;
pform_time_prec = prec;
}
void pform_push_scope(const string&name)
{
scope_name_t*cur = new scope_name_t;
@@ -119,8 +109,6 @@ void pform_startmodule(const string&name, svector<Module::port_t*>*ports)
}
pform_cur_module = new Module(name, ports);
pform_cur_module->time_unit = pform_time_unit;
pform_cur_module->time_precision = pform_time_prec;
delete ports;
}
@@ -137,52 +125,6 @@ bool pform_expression_is_constant(const PExpr*ex)
return ex->is_constant(pform_cur_module);
}
MIN_TYP_MAX min_typ_max_flag = TYP;
unsigned min_typ_max_warn = 10;
PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max)
{
PExpr*res = 0;
switch (min_typ_max_flag) {
case MIN:
res = min;
delete typ;
delete max;
break;
case TYP:
res = typ;
delete min;
delete max;
break;
case MAX:
res = max;
delete min;
delete max;
break;
}
if (min_typ_max_warn > 0) {
cerr << res->get_line() << ": warning: choosing ";
switch (min_typ_max_flag) {
case MIN:
cerr << "min";
break;
case TYP:
cerr << "typ";
break;
case MAX:
cerr << "max";
break;
}
cerr << " expression." << endl;
min_typ_max_warn -= 1;
}
return res;
}
void pform_make_udp(const char*name, list<string>*parms,
svector<PWire*>*decl, list<string>*table,
Statement*init_expr)
@@ -323,32 +265,12 @@ void pform_make_udp(const char*name, list<string>*parms,
delete init_expr;
}
/*
* This is invoked to make a named event. This is the declaration of
* the event, and not necessarily the use of it.
*/
static void pform_make_event(const string&name, const string&fn, unsigned ln)
{
PEvent*event = new PEvent(name);
event->set_file(fn);
event->set_lineno(ln);
pform_cur_module->events[name] = event;
}
void pform_make_events(const list<string>*names, const string&fn, unsigned ln)
{
list<string>::const_iterator cur;
for (cur = names->begin() ; cur != names->end() ; cur++)
pform_make_event(*cur, fn, ln);
}
/*
* pform_makegates is called when a list of gates (with the same type)
* are ready to be instantiated. The function runs through the list of
* gates and calls the pform_makegate function to make the individual gate.
*/
void pform_makegate(PGBuiltin::Type type,
struct str_pair_t str,
svector<PExpr*>* delay,
const lgate&info)
{
@@ -363,8 +285,6 @@ void pform_makegate(PGBuiltin::Type type,
if (info.range[0])
cur->set_range(info.range[0], info.range[1]);
cur->strength0(str.str0);
cur->strength1(str.str1);
cur->set_file(info.file);
cur->set_lineno(info.lineno);
@@ -372,12 +292,10 @@ void pform_makegate(PGBuiltin::Type type,
}
void pform_makegates(PGBuiltin::Type type,
struct str_pair_t str,
svector<PExpr*>*delay,
svector<lgate>*gates)
svector<PExpr*>*delay, svector<lgate>*gates)
{
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
pform_makegate(type, str, delay, (*gates)[idx]);
pform_makegate(type, delay, (*gates)[idx]);
}
delete gates;
@@ -385,15 +303,12 @@ void pform_makegates(PGBuiltin::Type type,
/*
* A module is different from a gate in that there are different
* constraints, and sometimes different syntax. The X_modgate
* functions handle the instantaions of modules (and UDP objects) by
* making PGModule objects.
* constraints, and sometimes different syntax.
*/
static void pform_make_modgate(const string&type,
const string&name,
struct parmvalue_t*overrides,
svector<PExpr*>*overrides,
svector<PExpr*>*wires,
PExpr*msb, PExpr*lsb,
const string&fn, unsigned ln)
{
if (name == "") {
@@ -403,35 +318,16 @@ static void pform_make_modgate(const string&type,
return;
}
PGModule*cur = new PGModule(type, name, wires);
PGate*cur = new PGModule(type, name, overrides, wires);
cur->set_file(fn);
cur->set_lineno(ln);
cur->set_range(msb,lsb);
if (overrides && overrides->by_name) {
unsigned cnt = overrides->by_name->count();
named<PExpr*>*byname = new named<PExpr*>[cnt];
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
portname_t*curp = (*overrides->by_name)[idx];
byname[idx].name = curp->name;
byname[idx].parm = curp->parm;
}
cur->set_parameters(byname, cnt);
} else if (overrides && overrides->by_order) {
cur->set_parameters(overrides->by_order);
}
pform_cur_module->add_gate(cur);
}
static void pform_make_modgate(const string&type,
const string&name,
struct parmvalue_t*overrides,
svector<PExpr*>*overrides,
svector<portname_t*>*bind,
PExpr*msb, PExpr*lsb,
const string&fn, unsigned ln)
{
if (name == "") {
@@ -442,79 +338,37 @@ static void pform_make_modgate(const string&type,
}
unsigned npins = bind->count();
named<PExpr*>*pins = new named<PExpr*>[npins];
PGModule::bind_t*pins = new PGModule::bind_t[npins];
for (unsigned idx = 0 ; idx < npins ; idx += 1) {
portname_t*curp = (*bind)[idx];
pins[idx].name = curp->name;
pins[idx].parm = curp->parm;
}
PGModule*cur = new PGModule(type, name, pins, npins);
PGate*cur = new PGModule(type, name, overrides, pins, npins);
cur->set_file(fn);
cur->set_lineno(ln);
cur->set_range(msb,lsb);
if (overrides && overrides->by_name) {
unsigned cnt = overrides->by_name->count();
named<PExpr*>*byname = new named<PExpr*>[cnt];
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
portname_t*curp = (*overrides->by_name)[idx];
byname[idx].name = curp->name;
byname[idx].parm = curp->parm;
}
cur->set_parameters(byname, cnt);
} else if (overrides && overrides->by_order) {
cur->set_parameters(overrides->by_order);
}
pform_cur_module->add_gate(cur);
}
void pform_make_modgates(const string&type,
struct parmvalue_t*overrides,
svector<PExpr*>*overrides,
svector<lgate>*gates)
{
if (overrides && overrides->by_order)
for (unsigned idx = 0 ; idx < overrides->by_order->count() ; idx += 1)
if (! pform_expression_is_constant((*overrides->by_order)[idx])) {
VLerror("error: Parameter override expression"
" must be constant.");
return;
}
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
lgate cur = (*gates)[idx];
if (cur.parms_by_name) {
pform_make_modgate(type, cur.name, overrides,
cur.parms_by_name,
cur.range[0], cur.range[1],
pform_make_modgate(type, cur.name, overrides, cur.parms_by_name,
cur.file, cur.lineno);
} else if (cur.parms) {
/* If there are no parameters, the parser will be
tricked into thinking it is one empty
parameter. This fixes that. */
if ((cur.parms->count() == 1) && (cur.parms[0][0] == 0)) {
delete cur.parms;
cur.parms = new svector<PExpr*>(0);
}
pform_make_modgate(type, cur.name, overrides,
cur.parms,
cur.range[0], cur.range[1],
cur.file, cur.lineno);
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, overrides,
wires,
cur.range[0], cur.range[1],
cur.file, cur.lineno);
pform_make_modgate(type, cur.name, overrides, wires, cur.file,
cur.lineno);
}
}
@@ -522,8 +376,7 @@ void pform_make_modgates(const string&type,
}
PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
svector<PExpr*>*del,
struct str_pair_t str)
svector<PExpr*>*del)
{
svector<PExpr*>*wires = new svector<PExpr*>(2);
(*wires)[0] = lval;
@@ -536,69 +389,24 @@ PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
else
cur = new PGAssign(wires, del);
cur->strength0(str.str0);
cur->strength1(str.str1);
pform_cur_module->add_gate(cur);
return cur;
}
void pform_make_pgassign_list(svector<PExpr*>*alist,
svector<PExpr*>*del,
struct str_pair_t str,
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, str);
(*alist)[2*idx+1], del);
tmp->set_file(text);
tmp->set_lineno(lineno);
}
}
/*
* this function makes the initial assignment to a register as given
* in the source. It handles the case where a reg variable is assigned
* where it it declared:
*
* reg foo = <expr>;
*
* This is equivilent to the combination of statements:
*
* reg foo;
* initital foo = <expr>;
*
* and that is how it is parsed. This syntax is not part of the
* IEEE1364-1994 standard, but is approved by OVI as enhancement
* BTF-B14.
*/
void pform_make_reginit(const struct vlltype&li,
const string&name, PExpr*expr)
{
const string sname = scoped_name(name);
PWire*cur = pform_cur_module->get_wire(sname);
if (cur == 0) {
VLerror(li, "internal error: reginit to non-register?");
delete expr;
return;
}
PEIdent*lval = new PEIdent(sname);
lval->set_file(li.text);
lval->set_lineno(li.first_line);
PAssign*ass = new PAssign(lval, expr);
ass->set_file(li.text);
ass->set_lineno(li.first_line);
PProcess*top = new PProcess(PProcess::PR_INITIAL, ass);
top->set_file(li.text);
top->set_lineno(li.first_line);
pform_cur_module->add_behavior(top);
}
void pform_makewire(const vlltype&li, const string&nm,
NetNet::Type type)
{
@@ -608,7 +416,7 @@ void pform_makewire(const vlltype&li, const string&nm,
if (cur->get_wire_type() != NetNet::IMPLICIT) {
strstream msg;
msg << name << " previously defined at " <<
cur->get_line() << "." << ends;
cur->get_line() << ".";
VLerror(msg.str());
} else {
bool rc = cur->set_wire_type(type);
@@ -633,13 +441,12 @@ void pform_makewire(const vlltype&li, const list<string>*names,
}
void pform_set_port_type(const string&nm, NetNet::PortType pt)
void pform_set_port_type(const string&name, NetNet::PortType pt)
{
const string name = scoped_name(nm);
PWire*cur = pform_cur_module->get_wire(name);
if (cur == 0) {
cur = new PWire(name, NetNet::IMPLICIT, pt);
pform_cur_module->add_wire(cur);
VLerror("name is not a port.");
return;
}
if (! cur->set_port_type(pt))
@@ -748,16 +555,8 @@ void pform_set_function(const string&name, svector<PExpr*>*ra, PFunction *func)
void pform_set_attrib(const string&name, const string&key, const string&value)
{
PWire*cur = pform_cur_module->get_wire(name);
if (PWire*cur = pform_cur_module->get_wire(name)) {
cur->attributes[key] = value;
} else if (PGate*cur = pform_cur_module->get_gate(name)) {
cur->attributes[key] = value;
} else {
VLerror("Unable to match name for setting attribute.");
}
assert(cur);
cur->attributes[key] = value;
}
/*
@@ -825,23 +624,10 @@ void pform_set_net_range(list<string>*names, const svector<PExpr*>*range)
void pform_set_parameter(const string&name, PExpr*expr)
{
assert(expr);
pform_cur_module->parameters[name] = expr;
pform_cur_module->param_names.push_back(name);
}
void pform_set_localparam(const string&name, PExpr*expr)
{
assert(expr);
pform_cur_module->localparams[name] = expr;
}
void pform_set_defparam(const string&name, PExpr*expr)
{
assert(expr);
pform_cur_module->defparms[name] = expr;
}
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
{
for (list<string>::const_iterator cur = names->begin()
@@ -921,7 +707,6 @@ int pform_parse(const char*path, map<string,Module*>&modules,
int rc = VLparse();
if (rc) {
cerr << "I give up." << endl;
error_count += 1;
}
modules = vl_modules;
@@ -932,63 +717,6 @@ int pform_parse(const char*path, map<string,Module*>&modules,
/*
* $Log: pform.cc,v $
* Revision 1.64 2000/09/13 16:32:26 steve
* Error message for invalid variable list.
*
* Revision 1.63 2000/07/29 17:58:21 steve
* Introduce min:typ:max support.
*
* Revision 1.62 2000/07/22 22:09:04 steve
* Parse and elaborate timescale to scopes.
*
* Revision 1.61 2000/05/23 16:03:13 steve
* Better parsing of expressions lists will empty expressoins.
*
* Revision 1.60 2000/05/16 04:05:16 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.59 2000/05/08 05:30:20 steve
* Deliver gate output strengths to the netlist.
*
* Revision 1.58 2000/05/06 15:41:57 steve
* Carry assignment strength to pform.
*
* Revision 1.57 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.56 2000/03/12 17:09:41 steve
* Support localparam.
*
* Revision 1.55 2000/03/08 04:36:54 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.54 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.53 2000/02/18 05:15:03 steve
* Catch module instantiation arrays.
*
* Revision 1.52 2000/01/09 05:50:49 steve
* Support named parameter override lists.
*
* Revision 1.51 2000/01/02 01:59:28 steve
* Forgot to handle no overrides at all.
*
* Revision 1.50 2000/01/01 23:47:58 steve
* Fix module parameter override syntax.
*
* Revision 1.49 1999/12/30 19:06:14 steve
* Support reg initial assignment syntax.
*
* Revision 1.48 1999/12/11 05:45:41 steve
* Fix support for attaching attributes to primitive gates.
*
* Revision 1.47 1999/11/23 01:04:57 steve
* A file name of - means standard input.
*
@@ -1023,5 +751,155 @@ int pform_parse(const char*path, map<string,Module*>&modules,
* Revision 1.37 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
*
* Revision 1.36 1999/08/01 16:34:50 steve
* Parse and elaborate rise/fall/decay times
* for gates, and handle the rules for partial
* lists of times.
*
* Revision 1.35 1999/07/31 19:15:21 steve
* misspelled comment.
*
* Revision 1.34 1999/07/31 19:14:47 steve
* Add functions up to elaboration (Ed Carter)
*
* Revision 1.33 1999/07/24 02:11:20 steve
* Elaborate task input ports.
*
* Revision 1.32 1999/07/10 01:03:18 steve
* remove string from lexical phase.
*
* Revision 1.31 1999/07/03 02:12:52 steve
* Elaborate user defined tasks.
*
* Revision 1.30 1999/06/24 04:24:18 steve
* Handle expression widths for EEE and NEE operators,
* add named blocks and scope handling,
* add registers declared in named blocks.
*
* Revision 1.29 1999/06/21 01:02:16 steve
* Fix merging of UDP port type in decls.
*
* Revision 1.28 1999/06/17 05:34:42 steve
* Clean up interface of the PWire class,
* Properly match wire ranges.
*
* Revision 1.27 1999/06/15 03:44:53 steve
* Get rid of the STL vector template.
*
* Revision 1.26 1999/06/13 23:51:16 steve
* l-value part select for procedural assignments.
*
* Revision 1.25 1999/06/12 20:35:27 steve
* parse more verilog.
*
* Revision 1.24 1999/06/12 03:42:17 steve
* Assert state of bit range expressions.
*
* Revision 1.23 1999/06/06 20:45:39 steve
* Add parse and elaboration of non-blocking assignments,
* Replace list<PCase::Item*> with an svector version,
* Add integer support.
*
* Revision 1.22 1999/06/02 15:38:46 steve
* Line information with nets.
*
* Revision 1.21 1999/05/31 15:45:59 steve
* makegates infinite loop fixed.
*
* Revision 1.20 1999/05/29 02:36:17 steve
* module parameter bind by name.
*
* Revision 1.19 1999/05/20 04:31:45 steve
* Much expression parsing work,
* mark continuous assigns with source line info,
* replace some assertion failures with Sorry messages.
*
* Revision 1.18 1999/05/16 05:08:42 steve
* Redo constant expression detection to happen
* after parsing.
*
* Parse more operators and expressions.
*
* Revision 1.17 1999/05/10 00:16:58 steve
* Parse and elaborate the concatenate operator
* in structural contexts, Replace vector<PExpr*>
* and list<PExpr*> with svector<PExpr*>, evaluate
* constant expressions with parameters, handle
* memories as lvalues.
*
* Parse task declarations, integer types.
*
* Revision 1.16 1999/05/08 20:19:20 steve
* Parse more things.
*
* Revision 1.15 1999/05/07 04:26:49 steve
* Parse more complex continuous assign lvalues.
*
* Revision 1.14 1999/05/06 04:37:17 steve
* Get rid of list<lgate> types.
*
* Revision 1.13 1999/05/06 04:09:28 steve
* Parse more constant expressions.
*
* Revision 1.12 1999/05/02 23:25:32 steve
* Enforce module instance names.
*
* Revision 1.11 1999/04/19 01:59:37 steve
* Add memories to the parse and elaboration phases.
*
* Revision 1.10 1999/02/21 17:01:57 steve
* Add support for module parameters.
*
* Revision 1.9 1999/02/15 02:06:15 steve
* Elaborate gate ranges.
*
* Revision 1.8 1999/01/25 05:45:56 steve
* Add the LineInfo class to carry the source file
* location of things. PGate, Statement and PProcess.
*
* elaborate handles module parameter mismatches,
* missing or incorrect lvalues for procedural
* assignment, and errors are propogated to the
* top of the elaboration call tree.
*
* Attach line numbers to processes, gates and
* assignment statements.
*
* Revision 1.7 1998/12/09 04:02:47 steve
* Support the include directive.
*
* Revision 1.6 1998/12/01 00:42:14 steve
* Elaborate UDP devices,
* Support UDP type attributes, and
* pass those attributes to nodes that
* are instantiated by elaboration,
* Put modules into a map instead of
* a simple list.
*
* Revision 1.5 1998/11/25 02:35:53 steve
* Parse UDP primitives all the way to pform.
*
* Revision 1.4 1998/11/23 00:20:23 steve
* NetAssign handles lvalues as pin links
* instead of a signal pointer,
* Wire attributes added,
* Ability to parse UDP descriptions added,
* XNF generates EXT records for signals with
* the PAD attribute.
*
* Revision 1.3 1998/11/11 00:01:51 steve
* Check net ranges in declarations.
*
* Revision 1.2 1998/11/07 17:05:06 steve
* Handle procedural conditional, and some
* of the conditional expressions.
*
* Elaborate signals and identifiers differently,
* allowing the netlist to hold signal information.
*
* Revision 1.1 1998/11/03 23:29:03 steve
* Introduce verilog to CVS.
*
*/
+8 -67
View File
@@ -1,7 +1,7 @@
#ifndef __pform_H
#define __pform_H
/*
* Copyright (c) 1998-2000 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
@@ -18,12 +18,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: pform.h,v 1.41 2000/07/29 17:58:21 steve Exp $"
#if !defined(WINNT)
#ident "$Id: pform.h,v 1.31 1999/09/10 05:02:09 steve Exp $"
#endif
# include "netlist.h"
# include "named.h"
# include "Module.h"
# include "Statement.h"
# include "PGate.h"
@@ -58,15 +57,6 @@ class PGate;
class PExpr;
struct vlltype;
/*
* The min:typ:max expression s selected at parse time using the
* enumeration. When the compiler makes a choise, it also prints a
* warning if min_typ_max_warn > 0.
*/
extern enum MIN_TYP_MAX { MIN, TYP, MAX } min_typ_max_flag;
extern unsigned min_typ_max_warn;
PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max);
/*
* These type are lexical types -- that is, types that are used as
* lexical values to decorate the parse tree during parsing. They are
@@ -75,16 +65,11 @@ PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max);
/* This is information about port name information for named port
connections. */
typedef struct named<PExpr*> portname_t;
struct parmvalue_t {
svector<PExpr*>*by_order;
svector<portname_t*>*by_name;
struct portname_t {
string name;
PExpr*parm;
};
struct str_pair_t { PGate::strength_t str0, str1; };
/* The lgate is gate instantiation information. */
struct lgate {
lgate(int =0)
@@ -131,8 +116,6 @@ extern void pform_makewire(const struct vlltype&li, const string&name,
NetNet::Type type = NetNet::IMPLICIT);
extern void pform_makewire(const struct vlltype&li, const list<string>*names,
NetNet::Type type);
extern void pform_make_reginit(const struct vlltype&li,
const string&name, PExpr*expr);
extern void pform_set_port_type(list<string>*names, NetNet::PortType);
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);
@@ -144,37 +127,29 @@ extern void pform_set_attrib(const string&name, const string&key,
extern void pform_set_type_attrib(const string&name, const string&key,
const string&value);
extern void pform_set_parameter(const string&name, PExpr*expr);
extern void pform_set_localparam(const string&name, PExpr*expr);
extern void pform_set_defparam(const string&name, PExpr*expr);
extern PProcess* pform_make_behavior(PProcess::Type, Statement*);
extern svector<PWire*>* pform_make_udp_input_ports(list<string>*);
extern bool pform_expression_is_constant(const PExpr*);
extern void pform_make_events(const list<string>*names,
const string&file, unsigned lineno);
/*
* The makegate function creates a new gate (which need not have a
* name) and connects it to the specified wires.
*/
extern void pform_makegates(PGBuiltin::Type type,
struct str_pair_t str,
svector<PExpr*>*delay,
svector<lgate>*gates);
extern void pform_make_modgates(const string&type,
struct parmvalue_t*overrides,
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,
struct str_pair_t str);
svector<PExpr*>*delays);
extern void pform_make_pgassign_list(svector<PExpr*>*alist,
svector<PExpr*>*del,
struct str_pair_t str,
const string& text,
unsigned lineno);
@@ -199,40 +174,6 @@ extern void pform_dump(ostream&out, Module*mod);
/*
* $Log: pform.h,v $
* Revision 1.41 2000/07/29 17:58:21 steve
* Introduce min:typ:max support.
*
* Revision 1.40 2000/05/08 05:30:20 steve
* Deliver gate output strengths to the netlist.
*
* Revision 1.39 2000/05/06 15:41:57 steve
* Carry assignment strength to pform.
*
* Revision 1.38 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.37 2000/03/12 17:09:41 steve
* Support localparam.
*
* Revision 1.36 2000/03/08 04:36:54 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.35 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.34 2000/01/10 22:16:24 steve
* minor type syntax fix for stubborn C++ compilers.
*
* Revision 1.33 2000/01/09 05:50:49 steve
* Support named parameter override lists.
*
* Revision 1.32 1999/12/30 19:06:14 steve
* Support reg initial assignment syntax.
*
* Revision 1.31 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
+39 -218
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: pform_dump.cc,v 1.62 2000/10/14 02:23:02 steve Exp $"
#if !defined(WINNT)
#ident "$Id: pform_dump.cc,v 1.45 1999/10/10 01:59:55 steve Exp $"
#endif
/*
@@ -27,7 +27,6 @@
* module in question.
*/
# include "pform.h"
# include "PEvent.h"
# include <iostream>
# include <iomanip>
# include <typeinfo>
@@ -44,30 +43,6 @@ ostream& operator << (ostream&o, const PDelays&d)
return o;
}
ostream& operator<< (ostream&o, PGate::strength_t str)
{
switch (str) {
case PGate::HIGHZ:
o << "highz";
break;
case PGate::WEAK:
o << "weak";
break;
case PGate::PULL:
o << "pull";
break;
case PGate::STRONG:
o << "strong";
break;
case PGate::SUPPLY:
o << "supply";
break;
default:
assert(0);
}
return o;
}
void PExpr::dump(ostream&out) const
{
out << typeid(*this).name();
@@ -83,12 +58,9 @@ void PEConcat::dump(ostream&out) const
return;
}
out << "{";
if (parms_[0]) out << *parms_[0];
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
out << ", ";
if (parms_[idx]) out << *parms_[idx];
}
out << "{" << *parms_[0];
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1)
out << ", " << *parms_[idx];
out << "}";
@@ -98,13 +70,10 @@ void PEConcat::dump(ostream&out) const
void PECallFunction::dump(ostream &out) const
{
out << name_ << "(";
if (parms_.count() > 0) {
if (parms_[0]) parms_[0]->dump(out);
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
out << ", ";
if (parms_[idx]) parms_[idx]->dump(out);
}
parms_[0]->dump(out);
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
out << ", ";
parms_[idx]->dump(out);
}
out << ")";
}
@@ -112,20 +81,19 @@ void PECallFunction::dump(ostream &out) const
void PEEvent::dump(ostream&out) const
{
switch (type_) {
case PEEvent::ANYEDGE:
case NetNEvent::ANYEDGE:
break;
case PEEvent::POSEDGE:
case NetNEvent::POSEDGE:
out << "posedge ";
break;
case PEEvent::NEGEDGE:
case NetNEvent::NEGEDGE:
out << "negedge ";
break;
case PEEvent::POSITIVE:
case NetNEvent::POSITIVE:
out << "positive ";
break;
}
out << *expr_;
}
void PENumber::dump(ostream&out) const
@@ -214,13 +182,9 @@ void PWire::dump(ostream&out) const
break;
}
assert(msb_.count() == lsb_.count());
for (unsigned idx = 0 ; idx < msb_.count() ; idx += 1) {
assert(msb_[idx]);
if (lsb_[idx])
out << " [" << *msb_[idx] << ":" << *lsb_[idx] << "]";
else
out << " [" << *msb_[idx] << "]";
assert(lsb_[idx] && msb_[idx]);
out << " [" << *msb_[idx] << ":" << *lsb_[idx] << "]";
}
out << " " << name_;
@@ -245,7 +209,7 @@ void PWire::dump(ostream&out) const
void PGate::dump_pins(ostream&out) const
{
if (pin_count()) {
if (pin(0)) out << *pin(0);
out << *pin(0);
for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) {
out << ", ";
@@ -283,7 +247,7 @@ void PGate::dump(ostream&out) const
void PGAssign::dump(ostream&out) const
{
out << " assign (" << strength0() << "0 " << strength1() << "1) ";
out << " assign ";
dump_delays(out);
out << " " << *pin(0) << " = " << *pin(1) << ";" << endl;
}
@@ -304,7 +268,6 @@ void PGBuiltin::dump(ostream&out) const
out << " builtin gate ";
}
out << "(" << strength0() << "0 " << strength1() << "1) ";
dump_delays(out);
out << " " << get_name();
@@ -320,10 +283,7 @@ void PGBuiltin::dump(ostream&out) const
void PGModule::dump(ostream&out) const
{
out << " " << type_ << " ";
// If parameters are overridden by order, dump them.
if (overrides_) {
assert(parms_ == 0);
out << "#(";
out << *((*overrides_)[0]);
for (unsigned idx = 1 ; idx < overrides_->count() ; idx += 1) {
@@ -331,31 +291,7 @@ void PGModule::dump(ostream&out) const
}
out << ") ";
}
// If parameters are overridden by name, dump them.
if (parms_) {
assert(overrides_ == 0);
out << "#(";
out << "." << parms_[0].name << "(" << *parms_[0].parm << ")";
for (unsigned idx = 1 ; idx < nparms_ ; idx += 1) {
out << ", ." << parms_[idx].name << "(" <<
*parms_[idx].parm << ")";
}
out << ") ";
}
out << get_name();
// If the module is arrayed, print the index expressions.
if (msb_ || lsb_) {
out << "[";
if (msb_) out << *msb_;
out << ":";
if (lsb_) out << *lsb_;
out << "]";
}
out << "(";
out << get_name() << "(";
if (pins_) {
out << "." << pins_[0].name << "(";
if (pins_[0].parm) out << *pins_[0].parm;
@@ -488,18 +424,6 @@ void PCondit::dump(ostream&out, unsigned ind) const
}
}
void PCAssign::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "assign " << *lval_ << " = " << *expr_
<< "; /* " << get_line() << " */" << endl;
}
void PDeassign::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "deassign " << *lval_ << "; /* "
<< get_line() << " */" << endl;
}
void PDelayStatement::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "#" << *delay_ << " /* " <<
@@ -512,12 +436,6 @@ void PDelayStatement::dump(ostream&out, unsigned ind) const
}
}
void PDisable::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "disable " << scope_ << "; /* "
<< get_line() << " */" << endl;
}
void PEventStatement::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "@(" << *(expr_[0]);
@@ -536,12 +454,6 @@ void PEventStatement::dump(ostream&out, unsigned ind) const
}
}
void PForce::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "force " << *lval_ << " = " << *expr_
<< "; /* " << get_line() << " */" << endl;
}
void PForever::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "forever /* " << get_line() << " */" << endl;
@@ -571,12 +483,6 @@ void PFunction::dump(ostream&out, unsigned ind) const
out << setw(ind) << "" << "/* NOOP */" << endl;
}
void PRelease::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "release " << *lval_ << "; /* "
<< get_line() << " */" << endl;
}
void PRepeat::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "repeat (" << *expr_ << ")" << endl;
@@ -608,10 +514,6 @@ void PTask::dump(ostream&out, unsigned ind) const
out << setw(ind) << "" << "/* NOOP */" << endl;
}
void PTrigger::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "-> " << event_ << ";" << endl;
}
void PWhile::dump(ostream&out, unsigned ind) const
{
@@ -647,9 +549,24 @@ void Module::dump(ostream&out) const
continue;
}
out << " ." << cur->name << "(" << *cur->expr[0];
for (unsigned wdx = 1 ; wdx < cur->expr.count() ; wdx += 1) {
out << ", " << *cur->expr[wdx];
switch (cur->wires[0]->get_port_type()) {
case NetNet::PINPUT:
out << " input ." << cur->name << "(";
break;
case NetNet::POUTPUT:
out << " output ." << cur->name << "(";
break;
case NetNet::PINOUT:
out << " inout ." << cur->name << "(";
break;
default:
out << " XXXX ." << cur->name << "(";
break;
}
out << cur->wires[0]->name();
for (unsigned wdx = 1 ; wdx < cur->wires.count() ; wdx += 1) {
out << ", " << cur->wires[wdx]->name();
}
out << ")" << endl;
@@ -665,37 +582,12 @@ void Module::dump(ostream&out) const
out << "/* ERROR */;" << endl;
}
for (parm_iter_t cur = localparams.begin()
; cur != localparams.end() ; cur ++) {
out << " localparam " << (*cur).first << " = ";
if ((*cur).second)
out << *(*cur).second << ";" << endl;
else
out << "/* ERROR */;" << endl;
}
for (parm_iter_t cur = defparms.begin()
; cur != defparms.end() ; cur ++) {
out << " defparam " << (*cur).first << " = ";
if ((*cur).second)
out << *(*cur).second << ";" << endl;
else
out << "/* ERROR */;" << endl;
}
for (map<string,PEvent*>::const_iterator cur = events.begin()
; cur != events.end() ; cur ++ ) {
PEvent*ev = (*cur).second;
out << " event " << ev->name() << "; // "
<< ev->get_line() << endl;
}
// Iterate through and display all the wires.
for (map<string,PWire*>::const_iterator wire = wires_.begin()
for (list<PWire*>::const_iterator wire = wires_.begin()
; wire != wires_.end()
; wire ++ ) {
(*wire).second->dump(out);
(*wire)->dump(out);
}
// Dump the task definitions.
@@ -783,77 +675,6 @@ void PUdp::dump(ostream&out) const
/*
* $Log: pform_dump.cc,v $
* Revision 1.62 2000/10/14 02:23:02 steve
* Check for missing concat subexpressions (PR#11)
*
* Revision 1.61 2000/07/26 05:08:07 steve
* Parse disable statements to pform.
*
* Revision 1.60 2000/05/23 16:03:13 steve
* Better parsing of expressions lists will empty expressoins.
*
* Revision 1.59 2000/05/16 04:05:16 steve
* Module ports are really special PEIdent
* expressions, because a name can be used
* many places in the port list.
*
* Revision 1.58 2000/05/11 23:37:27 steve
* Add support for procedural continuous assignment.
*
* Revision 1.57 2000/05/06 15:41:57 steve
* Carry assignment strength to pform.
*
* Revision 1.56 2000/05/04 03:37:59 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.55 2000/04/22 04:20:19 steve
* Add support for force assignment.
*
* Revision 1.54 2000/04/12 20:02:53 steve
* Finally remove the NetNEvent and NetPEvent classes,
* Get synthesis working with the NetEvWait class,
* and get started supporting multiple events in a
* wait in vvm.
*
* Revision 1.53 2000/04/12 04:23:58 steve
* Named events really should be expressed with PEIdent
* objects in the pform,
*
* Handle named events within the mix of net events
* and edges. As a unified lot they get caught together.
* wait statements are broken into more complex statements
* that include a conditional.
*
* Do not generate NetPEvent or NetNEvent objects in
* elaboration. NetEvent, NetEvWait and NetEvProbe
* take over those functions in the netlist.
*
* Revision 1.52 2000/04/01 19:31:57 steve
* Named events as far as the pform.
*
* Revision 1.51 2000/03/12 17:09:41 steve
* Support localparam.
*
* Revision 1.50 2000/03/08 04:36:54 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters
* in a separate pass over the pform. Once the scopes
* are generated, I can process overrides and evalutate
* paremeters before elaboration begins.
*
* Revision 1.49 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.48 2000/02/18 05:15:03 steve
* Catch module instantiation arrays.
*
* Revision 1.47 2000/01/09 20:37:57 steve
* Careful with wires connected to multiple ports.
*
* Revision 1.46 2000/01/09 05:50:49 steve
* Support named parameter override lists.
*
* Revision 1.45 1999/10/10 01:59:55 steve
* Structural case equals device.
*
+88
View File
@@ -0,0 +1,88 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@picturel.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* 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: propinit.cc,v 1.1 1998/12/20 02:05:41 steve Exp $"
#endif
/*
* The propinit function runs through the devices that can impose
* initial values in the netlist and propogates those values. The
* process works by first scanning the active devices for outputs that
* they generate.
*/
# include "netlist.h"
/*
* prop_sequdp_output takes the output from the located sequential UDP
* device and propogates it to the signals connected to it.
*/
static bool is_sequ_udp(const NetNode*net)
{
const NetUDP*udp;
if ((udp = dynamic_cast<const NetUDP*>(net)) == 0)
return false;
return udp->is_sequential();
}
static void prop_sequdp_output(NetUDP*udp)
{
/* Get from the UDP class the initial output value. */
verinum::V ival;
switch (udp->get_initial()) {
case '0':
ival = verinum::V0;
break;
case '1':
ival = verinum::V1;
break;
default:
ival = verinum::Vx;
break;
}
/* Take the output value and write it to all the NetNet pins
that are connected to the output pin. */
for (NetObj::Link*lnk = udp->pin(0).next_link()
; (*lnk) != udp->pin(0) ; lnk = lnk->next_link()) {
if (NetNet*sig = dynamic_cast<NetNet*>(lnk->get_obj()))
sig->set_ival(lnk->get_pin(), ival);
}
}
void propinit(Design*des)
{
des->clear_node_marks();
while (NetNode*net = des->find_node(&is_sequ_udp)) {
net->set_mark();
prop_sequdp_output(dynamic_cast<NetUDP*>(net));
}
}
/*
* $Log: propinit.cc,v $
* Revision 1.1 1998/12/20 02:05:41 steve
* Function to calculate wire initial value.
*
*/
+15 -91
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
* 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
@@ -16,8 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: set_width.cc,v 1.14 2000/06/18 03:29:52 steve Exp $"
#if !defined(WINNT)
#ident "$Id: set_width.cc,v 1.6 1999/10/05 06:19:46 steve Exp $"
#endif
/*
@@ -47,8 +47,8 @@ bool NetEBinary::set_width(unsigned w)
case 'l': // left shift (<<)
case 'r': // right shift (>>)
/* these operators are handled in the derived class. */
assert(0);
flag = left_->set_width(w);
expr_width(w);
break;
/* The default rule is that the operands of the binary
@@ -126,18 +126,10 @@ bool NetEBBits::set_width(unsigned w)
*/
bool NetEBComp::set_width(unsigned w)
{
bool flag = true;
return (w == 1);
}
/*
* There is nothing we can do to the operands of a division to make it
* confirm to the requested width. Force the context to pad or truncate.
*/
bool NetEBDiv::set_width(unsigned w)
{
return w == expr_width();
}
bool NetEBLogic::set_width(unsigned w)
{
bool flag;
@@ -147,15 +139,6 @@ bool NetEBLogic::set_width(unsigned w)
return (w == 1);
}
/*
* There is nothing we can do to the operands of a multiply to make it
* confirm to the requested width. Force the context to pad or truncate.
*/
bool NetEBMult::set_width(unsigned w)
{
return w == expr_width();
}
/*
* The shift operator allows the shift amount to have its own
* natural width. The width of the operator result is the width of the
@@ -163,15 +146,8 @@ bool NetEBMult::set_width(unsigned w)
*/
bool NetEBShift::set_width(unsigned w)
{
bool flag = true;
left_->set_width(w);
if (left_->expr_width() < w)
left_ = pad_to_width(left_, w);
expr_width(left_->expr_width());
flag = expr_width() == w;
bool flag;
flag = left_->set_width(w);
return flag;
}
@@ -200,34 +176,13 @@ bool NetEConcat::set_width(unsigned w)
bool NetEConst::set_width(unsigned w)
{
if (w > value_.len()) {
verinum tmp (verinum::V0, w);
for (unsigned idx = 0 ; idx < value_.len() ; idx += 1)
tmp.set(idx, value_[idx]);
if (w > value_.len())
return false;
value_ = tmp;
expr_width(w);
return true;
} else {
unsigned use_w = w;
bool flag = true;
// Don't reduce a number too small to hold all the
// significant bits.
for (unsigned idx = w ; idx < value_.len() ; idx += 1)
if (value_[idx] != verinum::V0)
use_w = idx+1;
verinum tmp (verinum::V0, use_w);
for (unsigned idx = 0 ; idx < use_w ; idx += 1)
tmp.set(idx, value_[idx]);
value_ = tmp;
expr_width(use_w);
return use_w == w;
}
assert(w <= value_.len());
value_ = verinum(value_, w);
expr_width(w);
return true;
}
bool NetEMemory::set_width(unsigned w)
@@ -244,11 +199,6 @@ bool NetEParam::set_width(unsigned)
return false;
}
bool NetESFunc::set_width(unsigned w)
{
return w == expr_width();
}
/*
* The signal should automatically pad with zeros to get to th desired
* width. Do not allow signal bits to be truncated, however.
@@ -294,44 +244,18 @@ bool NetEUnary::set_width(unsigned w)
case '~':
case '-':
flag = expr_->set_width(w);
expr_width(w);
break;
default:
flag = expr_width() == w;
break;
}
expr_width(w);
return flag;
}
/*
* $Log: set_width.cc,v $
* Revision 1.14 2000/06/18 03:29:52 steve
* Handle width expansion of shift operators.
*
* Revision 1.13 2000/05/04 03:37:59 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*
* Revision 1.12 2000/04/28 18:43:23 steve
* integer division in expressions properly get width.
*
* Revision 1.11 2000/04/26 03:33:32 steve
* Do not set width too small to hold significant bits.
*
* Revision 1.10 2000/04/21 02:46:42 steve
* Many Unary operators have known widths.
*
* Revision 1.9 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*
* Revision 1.8 2000/01/13 03:35:35 steve
* Multiplication all the way to simulation.
*
* Revision 1.7 2000/01/01 19:56:51 steve
* Properly expand/shrink constants in expressions.
*
* Revision 1.6 1999/10/05 06:19:46 steve
* Add support for reduction NOR.
*
+189
View File
@@ -0,0 +1,189 @@
/*
* 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: sigfold.cc,v 1.3 1999/11/06 04:51:11 steve Exp $"
#endif
# include "netlist.h"
/*
* Some targets require that a list of connections include exactly one
* signal. This processing step deletes excess signals to meet that
* requirement.
*
* If there is a ring that has more then one signal connected
* together, the following heuristic is used to choose which signal to
* keep:
*
* If the name of signal X is deeper in the design hierarchy then
* signal Y, keep signal Y.
*
* Else, if X is a bus that is not as wide as Y, keep signal Y.
*
* The result of this should be that signals of enclosing modules will
* be preferred over signals of instantiated modules, and bussed
* signals (vectors) will be preferred over scaler signals.
*
* The presence of attributes modifies the folding process, by placing
* restrictions on what is allowed.
*
* If two signals have an attribute key X, they can be folded
* only if X has the same value for both signals.
*
* If signal A has attribute X and signal B does not, then
* signals can be folded if B can take the attribute.
*
* All the pins in a vector have identical attributes.
*/
static unsigned depth(const string&sym)
{
unsigned cnt = 0;
for (unsigned idx = 0 ; idx < sym.length() ; idx += 1)
if (sym[idx] == '.')
cnt += 1;
return cnt;
}
static bool is_any_signal(const NetNet*)
{
return true;
}
static void clear_extra_signals(NetNet*net, unsigned npin)
{
const unsigned mydepth = depth(net->name());
NetObj*cur = net;
unsigned pin = npin;
for (net->pin(pin).next_link(cur, pin) ; cur != net ; ) {
// sig is the node I am going to try to subsume.
NetNet*sig = dynamic_cast<NetNet*>(cur);
// Skip the node if it isn't even a signal.
if (sig == 0) {
cur->pin(pin).next_link(cur, pin);
continue;
}
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig)) {
cerr << "internal warning: sigfold found NetTmp--"
"deleting it." << endl;
// save the next link, ...
NetObj*nxt;
unsigned pnxt;
cur->pin(pin).next_link(nxt, pnxt);
// disconnect the target signal, ...
sig->pin(pin).unlink();
// And onward.
cur = nxt;
pin = pnxt;
continue;
}
// Skip the node if it has incompatible attributes.
if (! net->has_compat_attributes(*sig)) {
// SPECIAL CASE!
if (sig->has_compat_attributes(*net)) {
net->pin(npin).unlink();
return;
}
cur->pin(pin).next_link(cur, pin);
continue;
}
// Skip the node if it is higher up.
if (depth(sig->name()) < mydepth) {
cur->pin(pin).next_link(cur, pin);
continue;
}
// Skip the node if it is a larger vector.
if (sig->pin_count() > net->pin_count()) {
cur->pin(pin).next_link(cur, pin);
continue;
}
// save the next link, ...
NetObj*nxt;
unsigned pnxt;
cur->pin(pin).next_link(nxt, pnxt);
// disconnect the target signal, ...
sig->pin(pin).unlink();
// And onward.
cur = nxt;
pin = pnxt;
}
}
static void delete_if_unconnected(NetNet*net)
{
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1)
if (net->pin(idx).is_linked())
return;
delete net;
}
void sigfold(Design*des)
{
des->clear_signal_marks();
while (NetNet*obj = des->find_signal(&is_any_signal)) {
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
clear_extra_signals(obj, idx);
obj->set_mark();
}
// After the disconnect step, I may have signals that are not
// connected to anything. Delete those.
des->clear_signal_marks();
while (NetNet*obj = des->find_signal(&is_any_signal)) {
obj->set_mark();
delete_if_unconnected(obj);
}
}
/*
* $Log: sigfold.cc,v $
* Revision 1.3 1999/11/06 04:51:11 steve
* Catch NetTmp objects.
*
* Revision 1.2 1998/12/02 04:37:13 steve
* Add the nobufz function to eliminate bufz objects,
* Object links are marked with direction,
* constant propagation is more careful with wide links,
* Signal folding is aware of attributes, and
* the XNF target can dump UDP objects based on LCA
* attributes.
*
* Revision 1.1 1998/11/16 05:03:53 steve
* Add the sigfold function that unlinks excess
* signal nodes, and add the XNF target.
*
*/
-47
View File
@@ -1,47 +0,0 @@
# $Id: README-solaris_pkg.txt,v 1.1 2000/06/16 18:58:45 steve Exp $
Notes about the solaris package.
I. Installing a prebuild solaris package
-----------------------------------------
To install the solaris package do the following as root on your machine:
1) uncompress the package using:
cp package_name.gz /tmp
cd /tmp
gunzip package_name.gz
where "package_name.gz" is the compressed binary package. It will
be named something like "verilog-0.3-SunOS-5.6-sparc.gz"
2) install the package using:
cd /tmp
pkgadd -d package_name
this will install the package. The package will be registered under the
name "IVLver"
II. Deinstalling the solaris package
-------------------------------------
To deinstall an installed solaris package do the following as root on your machine:
pkgrm IVLver
III. Notes on building a solaris package from sources
------------------------------------------------------
1) build and install verilog. Be sure and pick where the package should
install with the "--prefix=" argument to 'configure'
2) edit the 'pkginfo' file to update the version number and also set BASEDIR
to the same as the argument to "--prefix="
3) edit the 'prototype' file to add/removed files/directories from the list
of installed components.
4) run the 'mksolpkg' script to create the solaris package
-47
View File
@@ -1,47 +0,0 @@
#!/bin/sh
#
# mksolpkg
# a script to generate a native solaris package
#
if [ `whoami` != "root" ]; then
echo "you must be root to run this script"
exit 1
fi
# an ugly hack to get various bits of info
ver=`grep VERSION pkginfo | sed 's/"/ /g' | awk '{print $2}'`
basedir=`grep BASEDIR pkginfo | sed 's/"/ /g' | awk '{print $2}'`
name=`grep NAME pkginfo | sed 's/"/ /g' | awk '{print $2}'`
pkg=`grep PKG pkginfo | sed 's/"/ /g' | awk '{print $2}'`
arch=`grep ARCH pkginfo | sed 's/"/ /g' | awk '{print $2}'`
march=`uname -p`
if [ "$arch" != "$march" ]; then
echo "Warning: you have listed \"$arch\" in the pkginfo file but this machine"
echo " has a \"$march\" processor"
exit 1
fi
oslabel=`uname -s`-`uname -r`-$march
fname=$name-$ver-$oslabel
cp -f prototype $basedir
cp -f pkginfo $basedir
cd $basedir
pkgmk -o -r `pwd`
cd /var/spool/pkg
pkgtrans -s `pwd` /tmp/$fname all
cd /tmp
gzip -f $fname
echo "Your $oslabel package is left in /tmp/$fname.gz"
# cleanup
rm -f $basedir/prototype $basedir/pkginfo
rm -fr /var/spool/pkg/$pkg
-10
View File
@@ -1,10 +0,0 @@
PKG="IVLver"
NAME="verilog"
ARCH="sparc"
VERSION="0.3"
CATEGORY="application"
VENDOR="Icarus.com"
EMAIL="[email protected]"
PSTAMP="Stephen Williams"
BASEDIR="/usr/local"
CLASSES="none"
-22
View File
@@ -1,22 +0,0 @@
i pkginfo=./pkginfo
d none bin 0755 bin bin
f none bin/iverilog 0755 bin bin
d none include 0755 bin bin
f none include/vpi_priv.h 0644 bin bin
f none include/vpi_user.h 0644 bin bin
f none include/vvm.h 0644 bin bin
f none include/vvm_calltf.h 0644 bin bin
f none include/vvm_func.h 0644 bin bin
f none include/vvm_gates.h 0644 bin bin
f none include/vvm_nexus.h 0644 bin bin
f none include/vvm_signal.h 0644 bin bin
f none include/vvm_thread.h 0644 bin bin
d none lib 0755 bin bin
d none lib/ivl 0755 bin bin
f none lib/ivl/ivl 0755 bin bin
f none lib/ivl/ivlpp 0755 bin bin
f none lib/ivl/system.vpi 0644 bin bin
f none lib/libvvm.a 0644 bin bin
d none man 0755 bin bin
d none man/man1 0755 bin bin
f none man/man1/iverilog.1 0644 bin bin

Some files were not shown because too many files have changed in this diff Show More