mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-28 08:46:28 +02:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e67952240b |
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
Makefile
|
||||
parse.c
|
||||
parse.h
|
||||
parse.output
|
||||
lexor.c
|
||||
iverilog
|
||||
@@ -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
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
-186
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+6
-77
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
+3
-6
@@ -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
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
@@ -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
Reference in New Issue
Block a user