Compare commits

...
110 Commits
Author SHA1 Message Date
steve f949f96df1 Add non-const bit select in l-value of assignment. 1999-10-07 05:25:33 +00:00
steve 1d215998b2 Move the rvalue into NetAssign_ common code. 1999-10-06 05:06:16 +00:00
steve 492d76e71d The $finish task should work immediately. 1999-10-06 01:28:18 +00:00
steve 1cc68f745a == and != connected to the wrong pins of the compare. 1999-10-06 00:39:00 +00:00
steve 4d8c0c79d6 Add support for reduction NOR. 1999-10-05 06:19:46 +00:00
steve a7f48c86e2 Relaxed width handling for <= assignment. 1999-10-05 04:02:10 +00:00
steve 35e84f15d4 null target ignore assignment nodes. 1999-10-05 03:26:37 +00:00
steve d513cf8f60 sorry message for non-constant l-value bit select. 1999-10-05 02:00:06 +00:00
steve efdc1769e6 Add some vvm operators from Eric Aardoom. 1999-10-01 15:26:28 +00:00
steve e1c697a746 More resilient assignment to memory location. 1999-10-01 03:58:36 +00:00
steve 393c9ab108 Rewrite vvm output to separateclass declarations
from method definitions. This is required to allow
 for mutual referencing, for example by tasks.
1999-10-01 03:15:00 +00:00
steve efa5222c66 Handle mutual reference of tasks by elaborating
task definitions in two passes, like functions.
1999-09-30 21:28:34 +00:00
steve f068196272 Ignore user task definitions. 1999-09-30 21:27:29 +00:00
steve 8317d8707e Remember to declare the calee_ member. 1999-09-30 21:26:59 +00:00
steve ed9aeec591 catch non-constant delays as unsupported. 1999-09-30 17:22:33 +00:00
steve 0c1c826410 Accept white after . in portname tokens. 1999-09-30 04:51:14 +00:00
steve c63a3acf93 Elaborate ~^ and ~| operators. 1999-09-30 02:43:01 +00:00
steve b37fcf3593 Handle declaration of integers (including scope) in functions. 1999-09-30 01:22:37 +00:00
steve 6e486e9bcf Cope with errors during ternary operator elaboration. 1999-09-30 00:48:49 +00:00
steve 076cecb6cd Handle null returns from function_item 1999-09-30 00:48:04 +00:00
steve 42006ec5f1 LT supports different width objects. 1999-09-29 22:57:26 +00:00
steve db7044850a Move code to elab_expr.cc 1999-09-29 22:57:10 +00:00
steve 5ee7cfb854 Fix shift/reduce warnings and ?:. ([email protected]) 1999-09-29 22:56:31 +00:00
steve 93f05306e7 Standardize error/sorry messages. 1999-09-29 21:16:32 +00:00
steve 8e21f0f363 Handle some mor missing names. 1999-09-29 21:15:58 +00:00
steve b2f7f533f7 Standardize formatting of warning messages. 1999-09-29 21:15:31 +00:00
steve 2271fc9894 Handle empty named ports in the dump. 1999-09-29 20:23:53 +00:00
steve a64a33e65a Full case support 1999-09-29 18:36:02 +00:00
steve 3a415fb04c Useless assertion. 1999-09-29 02:53:33 +00:00
steve 0c7722ce7e Hashed keyword lookup for the lexor. 1999-09-29 01:50:35 +00:00
steve 86a283b9bc Support the $write system task, and have the
vpi_scan function free iterators as needed.
1999-09-29 01:41:18 +00:00
steve 0fb4ba7907 Allow expanding of additive operators. 1999-09-29 00:42:50 +00:00
steve f274c9cade Comment on where binary operator came from. 1999-09-29 00:42:25 +00:00
steve 4882f04945 Spelling fixes from Larry. 1999-09-29 00:03:27 +00:00
steve a8a2b3e8f3 Use files instead of strstreams for delayed output,
and fix a missing ends in case output code.
1999-09-28 23:45:09 +00:00
steve 900949ab56 Get the bit widths of unary operators that return one bit. 1999-09-28 03:11:29 +00:00
steve 9f30615a91 save the thread class name so that behaviors in tasks have it. 1999-09-28 03:11:09 +00:00
steve a964e0479b Generate code for repeat concatenations. 1999-09-28 01:53:37 +00:00
steve 6d7ac5d67b Proper syntax for method pointers. 1999-09-28 01:21:27 +00:00
steve 470b0d3d34 Support in vvm > and >= behavioral operators. 1999-09-28 01:13:15 +00:00
steve bb38653654 Parse system function calls. 1999-09-25 02:57:29 +00:00
steve fb678877d7 comment about system functions. 1999-09-25 02:56:37 +00:00
steve 64cc38f0eb The <= operator takes different width operands. 1999-09-23 04:39:52 +00:00
steve 1a21d2fe9d Support shift operators. 1999-09-23 03:56:57 +00:00
steve 095995f09c internal error message for funky comparison width. 1999-09-23 02:28:27 +00:00
steve 851daff66f comparison parameter width is self determined. 1999-09-23 02:27:50 +00:00
steve 1b7261a393 Update support list. 1999-09-23 01:49:28 +00:00
steve 1c41f8ebd2 Move set_width methods into a single file,
Add the NetEBLogic class for logic expressions,
 Fix error setting with of && in if statements.
1999-09-23 00:21:54 +00:00
steve 59b1b4c7b9 Expand bits in delayed assignments. 1999-09-22 21:25:42 +00:00
steve 0955058fbe Catch parallel blocks in vvm emit. 1999-09-22 16:57:23 +00:00
steve 12b9071f49 Parse and elaborate named for/join blocks. 1999-09-22 04:30:04 +00:00
steve 357461b034 Fix solaris compatibility w/ send and getopt. 1999-09-22 02:13:57 +00:00
steve 4a0e7d56bd Document the new -x flag. 1999-09-22 02:12:15 +00:00
steve da4a7ea80a assignment with blocking event delay. 1999-09-22 02:00:48 +00:00
steve fcfa9d004a Get scope right when setting the net range. 1999-09-21 00:58:33 +00:00
steve 349f9ae302 Support parameters that reference other paramters. 1999-09-21 00:13:40 +00:00
steve 3a5e55b229 Elaborate parameters in phases. 1999-09-20 02:21:10 +00:00
steve 1f44822510 dump the repeat count, if applicable. 1999-09-19 01:06:36 +00:00
steve 6df3febada up to date wrt bugs and the verilog command. 1999-09-18 22:24:24 +00:00
steve 5fde1b3e05 Match bit widths comming out of task output ports. 1999-09-18 22:23:50 +00:00
steve fbf104bf4d report non-constant part select expressions. 1999-09-18 02:51:35 +00:00
steve dab04c221d Detect constant lessthen-equal expressions. 1999-09-18 01:53:08 +00:00
steve 251eb4f38f Remove spurious message. 1999-09-18 01:52:48 +00:00
steve 424e6a750c Handle unconnected module ports. 1999-09-17 02:06:25 +00:00
steve 4594ac1c2c elaborate concatenation repeats. 1999-09-16 04:18:15 +00:00
steve d904aceb2c More liberal matching of include and define. 1999-09-16 00:49:05 +00:00
steve a890724b40 Handle implicit !=0 in if statements. 1999-09-16 00:33:45 +00:00
steve 31bdb87c8f separate assign lval elaboration for error checking. 1999-09-15 04:17:52 +00:00
steve b04148b754 Elaborate non-blocking assignment to memories. 1999-09-15 01:55:06 +00:00
steve f36c511c2f Fix output name generation. (Stefan Peterson) 1999-09-15 01:47:39 +00:00
steve 39bc45ce67 implicitly declare wires if needed. 1999-09-14 01:50:52 +00:00
steve 3d78b558bc Handle gates without delays. 1999-09-14 01:50:35 +00:00
steve 54d38ac057 Update verilog.sh to use getopt and handle multiple files. 1999-09-14 01:50:06 +00:00
steve 7a211b9136 Clarify msb/lsb in context of netlist. Properly
handle part selects in lval and rval of expressions,
 and document where the least significant bit goes
 in NetNet objects.
1999-09-13 03:10:59 +00:00
steve 6847dac5c2 fix parsing of sized octal digits. 1999-09-13 03:08:52 +00:00
steve a3e9a7417d fix vpiHexStrVal dumping of digits to strings. 1999-09-13 03:08:10 +00:00
steve 25d6912217 Pad r-values in certain assignments. 1999-09-12 01:16:51 +00:00
steve 1c238f1948 Support ternary and <= operators in vvm. 1999-09-11 04:43:17 +00:00
steve 287d21f300 Handle integers at task parameters. 1999-09-10 05:02:09 +00:00
steve a6c6ac2191 Add ternary elaboration. 1999-09-10 04:04:06 +00:00
steve d6fbc30cd5 Allow assign to not match rvalue width. 1999-09-08 04:05:30 +00:00
steve 9d82d19d07 Empty conditionals ([email protected]) 1999-09-08 02:24:39 +00:00
steve 006a2cce83 Take multiple source files on the command line. 1999-09-05 22:33:18 +00:00
steve 8f68a07476 Add support for delayed non-blocking assignments. 1999-09-04 19:11:45 +00:00
steve 555d447180 Generate fake adder code in vvm. 1999-09-04 01:57:15 +00:00
steve 41a1c6bb02 elaborate the binary plus operator. 1999-09-03 04:28:38 +00:00
steve 6fb7120158 Parse non-blocking assignment delays. 1999-09-02 01:59:27 +00:00
steve 9f7eb4a935 Handle recursive functions and arbitrary function
references to other functions, properly pass
 function parameters and save function results.
1999-09-01 20:46:19 +00:00
steve 5ee83fce70 Dont install veriuser.h. 1999-08-31 23:00:08 +00:00
steve e69345b9fe Elaborate and emit to vvm procedural functions. 1999-08-31 22:38:29 +00:00
steve 1c11c864d5 man page for the verilog front end. 1999-08-31 22:34:25 +00:00
steve 58d05dfca2 Updates from Stefan. 1999-08-31 22:25:52 +00:00
steve 7d71abaa05 man page for the verilog front end. 1999-08-31 22:25:02 +00:00
steve 6b3b6f3384 Makefile install targets. 1999-08-28 02:10:57 +00:00
steve 0fe25f68f9 Call the right vpiFinish code. 1999-08-28 02:10:44 +00:00
steve 3017636c05 continuous assignment lists. 1999-08-27 15:08:37 +00:00
steve 23acca48ff elaborate some aspects of functions. 1999-08-25 22:22:41 +00:00
steve 648e4c68e4 handle bufz in XNF backend. 1999-08-25 22:22:08 +00:00
steve 9eae940ebd Parameter overrides support from Peter Monta
AND and XOR support wide expressions.
1999-08-23 16:48:39 +00:00
steve 0175a4fce0 xilinx support from Larry Doolittle 1999-08-20 15:08:57 +00:00
steve aba4a877db Add vpi_sim_control 1999-08-19 02:51:03 +00:00
steve 031d91f813 Fixup spelling and some error messages. <[email protected]> 1999-08-18 04:00:02 +00:00
steve f1fdce78be Update compile command line. 1999-08-18 03:45:36 +00:00
steve b119613a8a credit 1999-08-18 03:45:21 +00:00
steve 567badc7af declare vou_sim_control 1999-08-18 03:44:49 +00:00
steve b62f094874 Add the verilog.sh script. 1999-08-17 15:57:43 +00:00
steve 28c0691b5f uninstall uninstalls everything. 1999-08-15 02:20:06 +00:00
steve 2d0e11283d Convert vvm to implement system tasks with vpi. 1999-08-15 01:23:56 +00:00
steve f1825c54a7 Mention the sigfold function. 1999-08-14 22:48:21 +00:00
steve cf1abfe38c Uninitialized low and high indices for single gate syntax 1999-08-08 20:06:06 +00:00
70 changed files with 7573 additions and 2074 deletions
+1
View File
@@ -6,6 +6,7 @@ ivl
dep
configure
Makefile
verilog
config.status
config.log
config.cache
+32 -6
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.11 1999/08/07 20:05:51 steve Exp $"
#ident "$Id: Makefile.in,v 1.20 1999/09/29 01:50:35 steve Exp $"
#
#
SHELL = /bin/sh
@@ -33,6 +33,7 @@ VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
mandir = @mandir@
includedir = $(prefix)/include
CC = @CC@
@@ -45,27 +46,40 @@ CPPFLAGS = @CPPFLAGS@ @DEFS@
CXXFLAGS = @CXXFLAGS@
LDFLAGS = @LDFLAGS@
all: ivl
all: ivl verilog
cd vpi ; make all
cd vvm ; make all
cd ivlpp ; make all
clean:
rm *.o parse.cc parse.cc.output parse.h dep/*.d lexor.cc
cd vpi ; make clean
cd vvm ; make clean
cd ivlpp ; make clean
TT = t-null.o t-verilog.o t-vvm.o t-xnf.o
FF = nobufz.o propinit.o sigfold.o xnfio.o xnfsyn.o
O = main.o cprop.o design_dump.o elaborate.o emit.o eval.o functor.o \
lexor.o mangle.o netlist.o parse.o parse_misc.o pform.o pform_dump.o \
verinum.o verireal.o target.o targets.o Module.o PExpr.o PGate.o \
O = main.o cprop.o design_dump.o elaborate.o elab_expr.o emit.o eval.o \
eval_tree.o functor.o \
lexor.o lexor_keyword.o mangle.o netlist.o pad_to_width.o \
parse.o parse_misc.o pform.o pform_dump.o \
set_width.o \
verinum.o verireal.o target.o targets.o Module.o PDelays.o PExpr.o PGate.o \
PTask.o PFunction.o PWire.o Statement.o \
$(FF) $(TT)
Makefile: Makefile.in config.status
./config.status
# Make the actual verilog program from the script template. This
# simply invloves editing the substitution strings in the script into
# the configured copy.
tmp1 = bindir
tmp2 = libdir
verilog: $(srcdir)/verilog.sh
sed -e 's;@$(tmp1)@;@bindir@;' -e 's;@$(tmp2)@;@libdir@;' < $< > $@
ivl: $O
$(CXX) $(CXXFLAGS) -o ivl $O
@@ -86,18 +100,30 @@ parse.h parse.cc: parse.y
lexor.cc: lexor.lex
flex -PVL -s -olexor.cc lexor.lex
install: all installdirs $(bindir)/ivl
install: all installdirs $(bindir)/verilog $(bindir)/ivl $(mandir)/man1/verilog.1
cd vpi ; make install
cd vvm ; make install
cd ivlpp ; make install
$(bindir)/verilog: ./verilog
$(INSTALL_PROGRAM) ./verilog $(bindir)/verilog
$(bindir)/ivl: ivl
$(INSTALL_PROGRAM) ./ivl $(bindir)/ivl
$(mandir)/man1/verilog.1: $(srcdir)/verilog.1
$(INSTALL_DATA) $(srcdir)/verilog.1 $(mandir)/man1/verilog.1
installdirs: mkinstalldirs
$(srcdir)/mkinstalldirs $(includedir) $(bindir)
uninstall:
rm -f $(bindir)/ivl
rm -f $(bindir)/verilog
rm -f $(mandir)/man1/verilog.1
cd vpi ; make uninstall
cd vvm ; make uninstall
cd ivlpp ; make uninstall
-include $(patsubst %.o, dep/%.d, $O)
+6 -1
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: Module.cc,v 1.6 1999/08/04 02:13:02 steve Exp $"
#ident "$Id: Module.cc,v 1.7 1999/09/17 02:06:25 steve Exp $"
#endif
# include "Module.h"
@@ -30,6 +30,8 @@ Module::Module(const string&name, const svector<Module::port_t*>*pp)
ports_ = *pp;
for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) {
port_t*cur = ports_[idx];
if (cur == 0)
continue;
for (unsigned jdx = 0 ; jdx < cur->wires.count() ; jdx += 1)
add_wire(cur->wires[jdx]);
}
@@ -99,6 +101,9 @@ PWire* Module::get_wire(const string&name)
/*
* $Log: Module.cc,v $
* Revision 1.7 1999/09/17 02:06:25 steve
* Handle unconnected module ports.
*
* Revision 1.6 1999/08/04 02:13:02 steve
* Elaborate module ports that are concatenations of
* module signals.
+14 -2
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: Module.h,v 1.8 1999/08/04 02:13:02 steve Exp $"
#ident "$Id: Module.h,v 1.9 1999/08/23 16:48:39 steve Exp $"
#endif
# include <list>
@@ -64,6 +64,14 @@ class Module {
into this map. */
map<string,PExpr*>parameters;
/* Parameters may be overridden at instantiation time;
the overrides do not contain explicit parameter names,
but rather refer to parameters in the order they
appear in the instantiated module. Therefore a
list of names in module-order is needed to pass from
a parameter-index to its name. */
list<string> param_names;
const string&get_name() const { return name_; }
void add_gate(PGate*gate);
@@ -85,7 +93,7 @@ class Module {
const list<PProcess*>& get_behaviors() const { return behaviors_; }
void dump(ostream&out) const;
bool elaborate(Design*, const string&path) const;
bool elaborate(Design*, const string&path, svector<PExpr*>*overrides_) const;
private:
const string name_;
@@ -105,6 +113,10 @@ class Module {
/*
* $Log: Module.h,v $
* Revision 1.9 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.8 1999/08/04 02:13:02 steve
* Elaborate module ports that are concatenations of
* module signals.
+103
View File
@@ -0,0 +1,103 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PDelays.cc,v 1.1 1999/09/04 19:11:46 steve Exp $"
#endif
# include "PDelays.h"
# include "PExpr.h"
# include "verinum.h"
PDelays::PDelays()
{
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
delay_[idx] = 0;
}
PDelays::~PDelays()
{
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
delete delay_[idx];
}
void PDelays::set_delay(PExpr*del)
{
assert(del);
assert(delay_[0] == 0);
delay_[0] = del;
}
void PDelays::set_delays(const svector<PExpr*>*del)
{
assert(del);
assert(del->count() <= 3);
for (unsigned idx = 0 ; idx < del->count() ; idx += 1)
delay_[idx] = (*del)[idx];
}
void PDelays::eval_delays(Design*des, const string&path,
unsigned long&rise_time,
unsigned long&fall_time,
unsigned long&decay_time) const
{
verinum*dv;
if (delay_[0]) {
dv = delay_[0]->eval_const(des, path);
assert(dv);
rise_time = dv->as_ulong();
delete dv;
if (delay_[1]) {
dv = delay_[1]->eval_const(des, path);
assert(dv);
fall_time = dv->as_ulong();
delete dv;
if (delay_[2]) {
dv = delay_[2]->eval_const(des, path);
assert(dv);
decay_time = dv->as_ulong();
delete dv;
} else {
if (rise_time < fall_time)
decay_time = rise_time;
else
decay_time = fall_time;
}
} else {
assert(delay_[2] == 0);
fall_time = rise_time;
decay_time = rise_time;
}
} else {
rise_time = 0;
fall_time = 0;
decay_time = 0;
}
}
/*
* $Log: PDelays.cc,v $
* Revision 1.1 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
*/
+67
View File
@@ -0,0 +1,67 @@
#ifndef __PDelays_H
#define __PDelays_H
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PDelays.h,v 1.1 1999/09/04 19:11:46 steve Exp $"
#endif
# include "svector.h"
# include <string>
class Design;
class PExpr;
class ostream;
/*
* Various PForm objects can carry delays. These delays include rise,
* fall and decay times. This class arranges to carry the triplet.
*/
class PDelays {
public:
PDelays();
~PDelays();
void set_delay(PExpr*);
void set_delays(const svector<PExpr*>*del);
void eval_delays(Design*des, const string&path,
unsigned long&rise_time,
unsigned long&fall_time,
unsigned long&decay_time) const;
void dump_delays(ostream&out) const;
private:
PExpr* delay_[3];
private: // not implemented
PDelays(const PDelays&);
PDelays& operator= (const PDelays&);
};
ostream& operator << (ostream&o, const PDelays&);
/*
* $Log: PDelays.h,v $
* Revision 1.1 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
*/
#endif
+37 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PExpr.cc,v 1.7 1999/07/22 02:05:20 steve Exp $"
#ident "$Id: PExpr.cc,v 1.10 1999/09/25 02:57:29 steve Exp $"
#endif
# include "PExpr.h"
@@ -38,14 +38,40 @@ bool PExpr::is_constant(Module*) const
return false;
}
NetNet* PExpr::elaborate_net(Design*des, const string&path,
unsigned long,
unsigned long,
unsigned long) const
{
cerr << "Don't know how to elaborate `" << *this
<< "' as gates." << endl;
return 0;
}
NetNet* PExpr::elaborate_lnet(Design*des, const string&path) const
{
cerr << get_line() << ": expression not valid in assign l-value: "
<< *this << endl;
return 0;
}
bool PEBinary::is_constant(Module*mod) const
{
return left_->is_constant(mod) && right_->is_constant(mod);
}
PECallFunction::PECallFunction(const string &n, const svector<PExpr *> &parms)
: name_(n), parms_(parms)
{
}
PECallFunction::~PECallFunction()
{
}
bool PEConcat::is_constant(Module *mod) const
{
bool constant = repeat_->is_constant(mod);
bool constant = repeat_? repeat_->is_constant(mod) : true;
for (unsigned i = 0; constant && i < parms_.count(); ++i) {
constant = constant && parms_[i]->is_constant(mod);
}
@@ -102,6 +128,15 @@ bool PETernary::is_constant(Module*) const
/*
* $Log: PExpr.cc,v $
* Revision 1.10 1999/09/25 02:57:29 steve
* Parse system function calls.
*
* Revision 1.9 1999/09/16 04:18:15 steve
* elaborate concatenation repeats.
*
* Revision 1.8 1999/09/15 04:17:52 steve
* separate assign lval elaboration for error checking.
*
* Revision 1.7 1999/07/22 02:05:20 steve
* is_constant method for PEConcat.
*
+38 -8
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PExpr.h,v 1.17 1999/08/01 21:18:55 steve Exp $"
#ident "$Id: PExpr.h,v 1.20 1999/09/25 02:57:29 steve Exp $"
#endif
# include <string>
@@ -47,11 +47,20 @@ class PExpr : public LineInfo {
virtual ~PExpr();
virtual void dump(ostream&) const;
// Procedural elaboration of the expression.
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
// This method elaborate the expression as gates, for use in a
// continuous assign or other wholy structural context.
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
// This method elaborates the expression as gates, but
// restricted for use as l-values of continuous assignments.
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
// This attempts to evaluate a constant expression, and return
// a verinum as a result. If the expression cannot be
@@ -80,6 +89,7 @@ class PEConcat : public PExpr {
~PEConcat();
virtual void dump(ostream&) const;
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned long rise =0,
unsigned long fall =0,
@@ -116,11 +126,18 @@ class PEIdent : public PExpr {
: text_(s), msb_(0), lsb_(0), idx_(0) { }
virtual void dump(ostream&) const;
// Identifiers are allowed (with restrictions) is assign l-values.
virtual NetNet* elaborate_lnet(Design*des, const string&path) const;
// Structural r-values are OK.
virtual NetNet* elaborate_net(Design*des, const string&path,
unsigned long rise =0,
unsigned long fall =0,
unsigned long decay =0) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
virtual bool is_constant(Module*) const;
verinum* eval_const(const Design*des, const string&path) const;
@@ -246,22 +263,35 @@ class PETernary : public PExpr {
PExpr*fal_;
};
/*
* This class represents a parsed call to a function.
*/
class PECallFunction : public PExpr {
public:
explicit PECallFunction(const string &n, const svector<PExpr *> &parms)
: name_(n), parms_(parms) {}
~PECallFunction() {}
public:
explicit PECallFunction(const string &n, const svector<PExpr *> &parms);
~PECallFunction();
virtual void dump(ostream &) const;
virtual NetExpr*elaborate_expr(Design*des, const string&path) const;
private:
private:
string name_;
svector<PExpr *> parms_;
NetESFunc* elaborate_sfunc_(Design*des, const string&path) const;
};
/*
* $Log: PExpr.h,v $
* Revision 1.20 1999/09/25 02:57:29 steve
* Parse system function calls.
*
* Revision 1.19 1999/09/15 04:17:52 steve
* separate assign lval elaboration for error checking.
*
* Revision 1.18 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.17 1999/08/01 21:18:55 steve
* elaborate rise/fall/decay for continuous assign.
*
+36 -1
View File
@@ -1,10 +1,45 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PFunction.cc,v 1.2 1999/08/25 22:22:41 steve Exp $"
#endif
#include "PTask.h"
PFunction::PFunction(svector<PWire*>*p, Statement*s)
: ports_(p), statement_(s)
: out_(0), ports_(p), statement_(s)
{
}
PFunction::~PFunction()
{
}
void PFunction::set_output(PWire*o)
{
assert(out_ == 0);
out_ = o;
}
/*
* $Log: PFunction.cc,v $
* Revision 1.2 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
*/
+10 -52
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PGate.cc,v 1.3 1999/08/01 21:18:55 steve Exp $"
#ident "$Id: PGate.cc,v 1.5 1999/09/14 01:50:35 steve Exp $"
#endif
# include "PGate.h"
@@ -30,14 +30,7 @@ PGate::PGate(const string&name,
const svector<PExpr*>*del)
: name_(name), pins_(pins)
{
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
delay_[idx] = 0;
if (del) {
assert(del->count() <= 3);
for (unsigned idx = 0 ; idx < del->count() ; idx += 1)
delay_[idx] = (*del)[idx];
}
if (del) delay_.set_delays(del);
}
PGate::PGate(const string&name,
@@ -45,23 +38,16 @@ PGate::PGate(const string&name,
PExpr*del)
: name_(name), pins_(pins)
{
delay_[0] = del;
delay_[1] = 0;
delay_[2] = 0;
if (del) delay_.set_delay(del);
}
PGate::PGate(const string&name, svector<PExpr*>*pins)
: name_(name), pins_(pins)
{
delay_[0] = 0;
delay_[1] = 0;
delay_[2] = 0;
}
PGate::~PGate()
{
for (unsigned idx = 0 ; idx < 3 ; idx += 1)
delete delay_[idx];
}
/*
@@ -77,41 +63,7 @@ void PGate::eval_delays(Design*des, const string&path,
unsigned long&fall_time,
unsigned long&decay_time) const
{
verinum*dv;
if (delay_[0]) {
dv = delay_[0]->eval_const(des, path);
assert(dv);
rise_time = dv->as_ulong();
delete dv;
if (delay_[1]) {
dv = delay_[1]->eval_const(des, path);
assert(dv);
fall_time = dv->as_ulong();
delete dv;
if (delay_[2]) {
dv = delay_[2]->eval_const(des, path);
assert(dv);
decay_time = dv->as_ulong();
delete dv;
} else {
if (rise_time < fall_time)
decay_time = rise_time;
else
decay_time = fall_time;
}
} else {
assert(delay_[2] == 0);
fall_time = rise_time;
decay_time = rise_time;
}
} else {
rise_time = 0;
fall_time = 0;
decay_time = 0;
}
delay_.eval_delays(des, path, rise_time, fall_time, decay_time);
}
PGAssign::PGAssign(svector<PExpr*>*pins)
@@ -160,6 +112,12 @@ void PGBuiltin::set_range(PExpr*msb, PExpr*lsb)
/*
* $Log: PGate.cc,v $
* Revision 1.5 1999/09/14 01:50:35 steve
* Handle gates without delays.
*
* Revision 1.4 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.3 1999/08/01 21:18:55 steve
* elaborate rise/fall/decay for continuous assign.
*
+15 -6
View File
@@ -19,11 +19,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PGate.h,v 1.8 1999/08/01 21:18:55 steve Exp $"
#ident "$Id: PGate.h,v 1.10 1999/09/04 19:11:46 steve Exp $"
#endif
# include "svector.h"
# include "LineInfo.h"
# include "PDelays.h"
class PExpr;
class PUdp;
class Design;
@@ -72,7 +73,7 @@ class PGate : public LineInfo {
private:
const string name_;
PExpr* delay_[3];
PDelays delay_;
svector<PExpr*>*pins_;
private: // not implemented
@@ -150,8 +151,8 @@ class PGModule : public PGate {
// If the binding of ports is by position, this constructor
// builds everything all at once.
explicit PGModule(const string&type, const string&name,
svector<PExpr*>*pins)
: PGate(name, pins), type_(type), pins_(0), npins_(0) { }
svector<PExpr*>*overrides, svector<PExpr*>*pins)
: PGate(name, pins), type_(type), overrides_(overrides), pins_(0), npins_(0) { }
// If the binding of ports is by name, this constructor takes
// the bindings and stores them for later elaboration.
@@ -160,8 +161,8 @@ class PGModule : public PGate {
PExpr* parm;
};
explicit PGModule(const string&type, const string&name,
bind_t*pins, unsigned npins)
: PGate(name, 0), type_(type), pins_(pins), npins_(npins) { }
svector<PExpr*>*overrides, bind_t*pins, unsigned npins)
: PGate(name, 0), type_(type), overrides_(overrides), pins_(pins), npins_(npins) { }
virtual void dump(ostream&out) const;
@@ -169,6 +170,7 @@ class PGModule : public PGate {
private:
string type_;
svector<PExpr*>*overrides_;
bind_t*pins_;
unsigned npins_;
@@ -178,6 +180,13 @@ class PGModule : public PGate {
/*
* $Log: PGate.h,v $
* Revision 1.10 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.9 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.8 1999/08/01 21:18:55 steve
* elaborate rise/fall/decay for continuous assign.
*
+32 -6
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PTask.h,v 1.3 1999/07/31 19:14:47 steve Exp $"
#ident "$Id: PTask.h,v 1.6 1999/09/30 21:28:34 steve Exp $"
#endif
# include "LineInfo.h"
@@ -38,7 +38,9 @@ class PTask : public LineInfo {
explicit PTask(svector<PWire*>*p, Statement*s);
~PTask();
virtual void elaborate(Design*des, const string&path) const;
void elaborate_1(Design*des, const string&path) const;
void elaborate_2(Design*des, const string&path) const;
void dump(ostream&, unsigned) const;
private:
@@ -50,21 +52,45 @@ class PTask : public LineInfo {
PTask& operator=(const PTask&);
};
/*
* The function is similar to a task (in this context) but there is a
* single output port and a set of input ports. The output port is the
* function return value.
*/
class PFunction : public LineInfo {
public:
explicit PFunction(svector<PWire *> *p, Statement *s);
public:
explicit PFunction(svector<PWire *>*p, Statement *s);
~PFunction();
//virtual void elaborate(Design *des, const string &path) const {}
void set_output(PWire*);
/* Functions are elaborated in 2 passes. */
void elaborate_1(Design *des, const string &path) const;
void elaborate_2(Design *des, const string &path) const;
void dump(ostream&, unsigned) const;
private:
private:
PWire*out_;
svector<PWire *> *ports_;
Statement *statement_;
};
/*
* $Log: PTask.h,v $
* Revision 1.6 1999/09/30 21:28:34 steve
* Handle mutual reference of tasks by elaborating
* task definitions in two passes, like functions.
*
* Revision 1.5 1999/09/01 20:46:19 steve
* Handle recursive functions and arbitrary function
* references to other functions, properly pass
* function parameters and save function results.
*
* Revision 1.4 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.3 1999/07/31 19:14:47 steve
* Add functions up to elaboration (Ed Carter)
*
+8 -1
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: PWire.cc,v 1.1 1999/06/17 05:34:42 steve Exp $"
#ident "$Id: PWire.cc,v 1.2 1999/09/10 05:02:09 steve Exp $"
#endif
# include "PWire.h"
@@ -41,6 +41,10 @@ bool PWire::set_wire_type(NetNet::Type t)
case NetNet::IMPLICIT:
type_ = t;
return true;
case NetNet::IMPLICIT_REG:
if (t == NetNet::REG) { type_ = t; return true; }
if (t == NetNet::INTEGER) {type_ = t; return true; }
return false;
case NetNet::REG:
if (t == NetNet::REG) return true;
if (t == NetNet::INTEGER) {type_ = t; return true; }
@@ -96,6 +100,9 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
/*
* $Log: PWire.cc,v $
* Revision 1.2 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
* Revision 1.1 1999/06/17 05:34:42 steve
* Clean up interface of the PWire class,
* Properly match wire ranges.
+89 -64
View File
@@ -1,12 +1,14 @@
THE ICARUS VERILOG COMPILATION SYSTEM
July 7, 1999
September 18, 1999
1.0 What is ICARUS Verilog(IVL)?
Icarus Verilog is intended to compile ALL of the Verilog HDL as described
in the IEEE-1364 standard. Of course, it's not quite there yet. It does
currently handle a mix of structural and behavioral constructs.
currently handle a mix of structural and behavioral constructs. For a
view of the current state of Icarus Verilog, see its home page at
<http://www.icarus.com/pub/verilog>.
IVL is not aimed at being a simulator in the traditional sense, but a
compiler that generates code employed by back-end tools. These back-
@@ -19,7 +21,7 @@ and an XNF (Xilinx Netlist Format) generator. See "vvm.txt" and
This tool includes a parser which reads in Verilog (plus extensions)
and generates an internal netlist. The netlist is passed to various
processing steps that transform the design to more optimal/practical
forms, then passed to a code generator for final output. The
forms, then is passed to a code generator for final output. The
processing steps and the code generator are selected by command line
switches.
@@ -27,15 +29,16 @@ switches.
There is a separate program, ivlpp, that does the preprocessing. This
program implements the `include and `define directives producing
output that is equivalent but without the directives. See
ivlpp/ivlpp.txt for details.
output that is equivalent but without the directives. The output is a
single file with line number directives, so that the actual compiler
only sees a single input file. See ivlpp/ivlpp.txt for details.
2.2 Parse
The verilog compiler starts by parsing the verilog source file. The
output of the parse in a list of Module objects in PFORM. The pform
(see pform.h) is mostly a direct reflection of the compilation
unit. There may be dangling references, and it is not yet clear which
step. There may be dangling references, and it is not yet clear which
module is the root.
One can see a human readable version of the final PFORM by using the
@@ -47,7 +50,8 @@ PFORM into the file named <path>.
This phase takes the pform and generates a netlist. The driver selects
(by user request or lucky guess) the root module to elaborate,
resolves references and expands the instantiations to form the design
netlist. (See netlist.txt.)
netlist. (See netlist.txt.) Final semantic checks are performed during
elaboration, and some simple optimizations are performed.
The elaborate() function performs the elaboration.
@@ -84,23 +88,27 @@ command line.
3.0 Building/Installing IVL
Unpack the tar-ball and cd into the verilog-######### directory.
Unpack the tar-ball and cd into the verilog-######### directory, and
compile the source with the commands:
./configure
make
cd vvm
make
./configure
make
Now install the files in an appropriate place. (The makefiles by
default install in /usr/local unless you specify a different prefix
with the --prefix=<path> flag to the configure command.) Do this as
root.
make install
cd vvm
make install
make install
4.0 Running IVL
4.0 Running Verilog
The preferred way to invoke the compiler with the verilog(1)
command. This program invokes the preprocessor (ivlpp) and the
compiler (ivl) with the proper command line options to get the job
done in a friendly way. See the verilog(1) man page for usage details.
4.1 Running IVL Directly
The ivl command is the compiler driver, that invokes the parser,
optimization functions and the code generator.
@@ -208,78 +216,89 @@ endmodule
--------------------------------------------------------------
Insure that "ivl" is on your search path, and the library
libvvm.a is available.
Insure that "verilog" is on your search path, and the vpi library
is available.
For csh -
setenv PATH /usr/local/bin:$PATH
setenv LD_LIBRARY_PATH /usr/local/lib:$LD_LIBRARY_PATH
setenv PATH /usr/local/bin:$PATH
setenv VPI_MODULE_PATH /usr/local/lib/ivl
ivl -t vvm -o hello.cc hello.vl
g++ hello.cc -o hello -lvvm
verilog hello.vl
(The above presumes that /usr/local/include and /usr/local/lib are
part of the compiler search path, which is usually the case for egcs.)
part of the compiler search path, which is usually the case for gcc.)
To run the program
./hello
./hello
5.0 Unsupported Constructs
IVL is in development - as such it still only supports a (growing) subset
of verilog. Below is a description of some of the currently unsupported
verilog features.
- The "?" operator. Example: count = val ? 1 : 0;
- Ranges within parameter definitions:
Example: parameter [15:0] seed = 16'ha3;
[Note: IEEE Std: 1364-1995 does not allow the syntax.]
- The "&&" operator:
Example: if (a && 0) do = 1;
- The "===" operator: Example: if( a === b) do = 1;
- The ">=" operator: Example: if ( a >= 0) do = 1;
- The ">" operator: Example: if ( a > 0) do = 1;
- The "<=" operator: Example: if ( a <= 0) do = 1;
- The "<<" shift operator: Example: a = 8'b0000_0010 << 1;
verilog features. This list is not exhaustive, and does not account
for errors in the compiler. See the Icarus Verilog web page for the
current state of support for Verilog.
- Min/Typ/Max expressions: Example: a = (1 : 6 : 14);
- Expansion of a string into a larger variable:
Example: reg [0:15] b; b = "b";
- Memories work, but only in procedural code.
- Function declarations/calls.
- Non-scalar memories, i.e. other than registers.
Example: reg [1:0] b [2:0];
- Delay list. Example: sample #(9,99) sample1(a,b);
- Bit ranges within IF. Example: if (a[2:3]) do = 1;
- Assignment timing delay: Example: a = #1 0; #1 a = #2 ~a;
- Bit Ranges within $write, $display.
reg [1:0] b [2:0], bar;
wire [1:0] foo;
always foo = b[i]; // sorry
always @(i) bar = b[i]; // OK
- `timescale directive
- Specify blocks
- force/release/assign/deassign procedural assignments not
supported.
- Named port parameters.
Example: module foo(.x(r[0])) ; reg r[7:0]; endmodule
- block disable not supported, i.e.:
begin : foo
[...]
disable foo; // sorry
[...]
end
- fork/join is not supported in vvm runtime
- structural arithmetic operators are in general not
supported. Procedural expressions are OK.
assign foo = a + b; // sorry
always @(a or b) foo = a + b; // OK
- Functions in structural contexts are not supported.
assign foo = user_function(a,b); // sorry
always @(a or b) foo = user_function(a,b); // OK
- multiplicative operators (*, /, %) are not supported.
assign foo = a * b; // sorry
always @(a or b) foo = a * b; // sorry
- event data type is not supported.
- real data type not supported.
- system functions are not supported. (User defined functions are
supported, and system tasks are supported.)
assign foo = $some_function(a,b); // sorry
always @(a or b) foo = $some_function(a,b); // sorry
- non-constant delay expressions, i.e.:
reg [7:0] del;
always #(reg) $display($time,,"del = %d", del); // sorry
Specify blocks are parsed but ignored in general.
Note that binding to a port by name does work from the outside.
i.e. ``foo foogate(.x(n[0]))'' is OK.
6.0 CREDITS
@@ -288,9 +307,15 @@ Williams. The proper notices are in the head of each file. However,
I have received aid in the form of fixes, Verilog guidance, and
especially testing from many people, including (in alphabetical order):
Eric Aardoom <[email protected]>
Ed Carter <[email protected]>
Larry Doolittle <[email protected]>
Guy Hutchison <[email protected]>
Ales Hvezda <[email protected]>
James Lee <[email protected]>
Peter Monta <[email protected]>
Daniel H. Nelsen <[email protected]>
Stefan Petersen <[email protected]>
Jason Schonberg <[email protected]>
Stuart Sutherland <[email protected]>
Stephen Tell <[email protected]>
+39 -7
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: Statement.cc,v 1.12 1999/07/12 00:59:36 steve Exp $"
#ident "$Id: Statement.cc,v 1.16 1999/09/29 18:36:02 steve Exp $"
#endif
# include "Statement.h"
@@ -27,20 +27,30 @@ Statement::~Statement()
{
}
PAssign_::PAssign_(PExpr*lval, PExpr*ex)
: event_(0), lval_(lval), rval_(ex)
{
}
PAssign_::PAssign_(PExpr*lval, PExpr*de, PExpr*ex)
: lval_(lval), delay_(de), rval_(ex)
: event_(0), lval_(lval), rval_(ex)
{
if (de) delay_.set_delay(de);
}
PAssign_::PAssign_(PExpr*lval, PEventStatement*ev, PExpr*ex)
: event_(ev), lval_(lval), rval_(ex)
{
}
PAssign_::~PAssign_()
{
delete lval_;
delete delay_;
delete rval_;
}
PAssign::PAssign(PExpr*lval, PExpr*ex)
: PAssign_(lval, 0, ex)
: PAssign_(lval, ex)
{
}
@@ -49,12 +59,22 @@ PAssign::PAssign(PExpr*lval, PExpr*d, PExpr*ex)
{
}
PAssign::PAssign(PExpr*lval, PEventStatement*d, PExpr*ex)
: PAssign_(lval, d, ex)
{
}
PAssign::~PAssign()
{
}
PAssignNB::PAssignNB(PExpr*lval, PExpr*ex)
: PAssign_(lval, 0, ex)
: PAssign_(lval, ex)
{
}
PAssignNB::PAssignNB(PExpr*lval, PExpr*d, PExpr*ex)
: PAssign_(lval, d, ex)
{
}
@@ -88,8 +108,8 @@ PCallTask::PCallTask(const string&n, const svector<PExpr*>&p)
{
}
PCase::PCase(PExpr*ex, svector<PCase::Item*>*l)
: expr_(ex), items_(l)
PCase::PCase(NetCase::TYPE t, PExpr*ex, svector<PCase::Item*>*l)
: type_(t), expr_(ex), items_(l)
{
}
@@ -143,6 +163,18 @@ PWhile::~PWhile()
/*
* $Log: Statement.cc,v $
* Revision 1.16 1999/09/29 18:36:02 steve
* Full case support
*
* Revision 1.15 1999/09/22 02:00:48 steve
* assignment with blocking event delay.
*
* Revision 1.14 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.13 1999/09/02 01:59:27 steve
* Parse non-blocking assignment delays.
*
* Revision 1.12 1999/07/12 00:59:36 steve
* procedural blocking assignment delays.
*
+33 -4
View File
@@ -19,15 +19,17 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: Statement.h,v 1.15 1999/07/12 00:59:36 steve Exp $"
#ident "$Id: Statement.h,v 1.20 1999/09/29 18:36:02 steve Exp $"
#endif
# include <string>
# include "svector.h"
# include "PDelays.h"
# include "PExpr.h"
# include "LineInfo.h"
class PExpr;
class Statement;
class PEventStatement;
/*
* The PProcess is the root of a behavioral process. Each process gets
@@ -77,11 +79,12 @@ class Statement : public LineInfo {
*/
class PAssign_ : public Statement {
public:
explicit PAssign_(PExpr*lval, PExpr*ex);
explicit PAssign_(PExpr*lval, PExpr*de, PExpr*ex);
explicit PAssign_(PExpr*lval, PEventStatement*de, PExpr*ex);
virtual ~PAssign_() =0;
const PExpr* lval() const { return lval_; }
const PExpr* delay() const { return delay_; }
const PExpr* rval() const { return rval_; }
protected:
@@ -89,9 +92,11 @@ class PAssign_ : public Statement {
unsigned&lsb, unsigned&msb,
NetExpr*&mux) const;
PDelays delay_;
PEventStatement*event_;
private:
PExpr* lval_;
PExpr* delay_;
PExpr* rval_;
};
@@ -100,6 +105,7 @@ class PAssign : public PAssign_ {
public:
explicit PAssign(PExpr*lval, PExpr*ex);
explicit PAssign(PExpr*lval, PExpr*de, PExpr*ex);
explicit PAssign(PExpr*lval, PEventStatement*de, PExpr*ex);
~PAssign();
virtual void dump(ostream&out, unsigned ind) const;
@@ -114,12 +120,15 @@ class PAssignNB : public PAssign_ {
public:
explicit PAssignNB(PExpr*lval, PExpr*ex);
explicit PAssignNB(PExpr*lval, PExpr*de, PExpr*ex);
~PAssignNB();
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
private:
NetProc*assign_to_memory_(class NetMemory*, PExpr*,
Design*des, const string&path) const;
};
/*
@@ -191,13 +200,14 @@ class PCase : public Statement {
Statement*stat;
};
PCase(PExpr*ex, svector<Item*>*);
PCase(NetCase::TYPE, PExpr*ex, svector<Item*>*);
~PCase();
virtual NetProc* elaborate(Design*des, const string&path) const;
virtual void dump(ostream&out, unsigned ind) const;
private:
NetCase::TYPE type_;
PExpr*expr_;
svector<Item*>*items_;
@@ -256,6 +266,10 @@ class PEventStatement : public Statement {
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, const string&path) const;
// This method is used to elaborate, but attach a previously
// elaborated statement to the event.
NetProc* elaborate_st(Design*des, const string&path, NetProc*st) const;
private:
svector<PEEvent*>expr_;
Statement*statement_;
@@ -333,6 +347,21 @@ class PWhile : public Statement {
/*
* $Log: Statement.h,v $
* Revision 1.20 1999/09/29 18:36:02 steve
* Full case support
*
* Revision 1.19 1999/09/22 02:00:48 steve
* assignment with blocking event delay.
*
* Revision 1.18 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.17 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.16 1999/09/02 01:59:27 steve
* Parse non-blocking assignment delays.
*
* Revision 1.15 1999/07/12 00:59:36 steve
* procedural blocking assignment delays.
*
+1 -1
View File
@@ -6,4 +6,4 @@ AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_OUTPUT(Makefile ivlpp/Makefile vvm/Makefile)
AC_OUTPUT(Makefile vpi/Makefile ivlpp/Makefile vvm/Makefile)
+171 -31
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: design_dump.cc,v 1.34 1999/08/01 16:34:50 steve Exp $"
#ident "$Id: design_dump.cc,v 1.48 1999/10/07 05:25:33 steve Exp $"
#endif
/*
@@ -121,26 +121,35 @@ void NetObj::dump_obj_attr(ostream&o, unsigned ind) const
}
}
void NetAddSub::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Adder (NetAddSub): " << name() << endl;
dump_node_pins(o, ind+4);
}
void NetAssign::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Procedural assign: " << *rval_ << endl;
o << setw(ind) << "" << "Procedural assign (NetAssign): " << name();
if (bmux())
o << "[" << *bmux() << "]";
o << " = " << *rval() << endl;
dump_node_pins(o, ind+4);
}
void NetAssignNB::dump_node(ostream&o, unsigned ind) const
{
if (bmux_)
o << setw(ind) << "" << "Procedural NB assign: " << name()
<< "[" << *bmux_ << "] <= " << *rval_ << endl;
if (bmux())
o << setw(ind) << "" << "Procedural NB assign (NetAssignNB): "
<< name() << "[" << *bmux() << "] <= " << *rval() << endl;
else
o << setw(ind) << "" << "Procedural NB assign: " << name()
<< " <= " << *rval_ << endl;
o << setw(ind) << "" << "Procedural NB assign (NetAssignNB): "
<< name() << " <= " << *rval() << endl;
dump_node_pins(o, ind+4);
}
void NetBUFZ::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "BUFZ: " << name() << endl;
o << setw(ind) << "" << "NetBUFZ: " << name() << endl;
dump_node_pins(o, ind+4);
}
@@ -327,28 +336,35 @@ void NetAssign::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "";
const NetNet*sig;
unsigned msb, lsb;
find_lval_range(sig, msb, lsb);
o << sig->name() << "[" << msb;
if (pin_count() > 1)
o << ":" << lsb;
o << "] = ";
rval_->dump(o);
o << ";" << endl;
if (bmux()) {
o << name() << "[" << *bmux() << "] = ";
if (rise_time())
o << "#" << rise_time() << " ";
o << *rval() << ";" << endl;
} else {
o << name() << " = ";
if (rise_time())
o << "#" << rise_time() << " ";
o << *rval() << ";" << endl;
}
}
void NetAssignNB::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "";
if (bmux_) {
o << name() << "[" << *bmux_ << "] <= " << *rval_ << ";" <<
endl;
if (bmux()) {
o << name() << "[" << *bmux() << "] <= ";
if (rise_time())
o << "#" << rise_time() << " ";
o << *rval() << ";" << endl;
} else {
o << name() << " <= " << *rval_ << ";" << endl;
o << name() << " <= ";
if (rise_time())
o << "#" << rise_time() << " ";
o << *rval() << ";" << endl;
}
}
@@ -357,10 +373,22 @@ void NetAssignMem::dump(ostream&o, unsigned ind) const
o << setw(ind) << "";
o << "/* " << get_line() << " */" << endl;
o << setw(ind) << "";
o << mem_->name() << "[";
index_->dump(o);
o << memory()->name() << "[";
index()->dump(o);
o << "] = ";
rval_->dump(o);
rval()->dump(o);
o << ";" << endl;
}
void NetAssignMemNB::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "";
o << "/* " << get_line() << " */" << endl;
o << setw(ind) << "";
o << memory()->name() << "[";
index()->dump(o);
o << "] <= ";
rval()->dump(o);
o << ";" << endl;
}
@@ -382,7 +410,14 @@ void NetBlock::dump(ostream&o, unsigned ind) const
void NetCase::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "case (" << *expr_ << ")" << endl;
switch (type_) {
case EQ:
o << setw(ind) << "" << "case (" << *expr_ << ")" << endl;
case EQX:
o << setw(ind) << "" << "casex (" << *expr_ << ")" << endl;
case EQZ:
o << setw(ind) << "" << "casez (" << *expr_ << ")" << endl;
}
for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) {
o << setw(ind+2) << "";
@@ -423,6 +458,15 @@ void NetForever::dump(ostream&o, unsigned ind) const
statement_->dump(o, ind+2);
}
void NetFuncDef::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "function " << name_ << endl;
if (statement_)
statement_->dump(o, ind+2);
else
o << setw(ind+2) << "" << "// NO STATEMENT" << endl;
}
void NetPDelay::dump(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "#" << delay_;
@@ -558,9 +602,15 @@ void NetEBinary::dump(ostream&o) const
case 'o':
o << "||";
break;
case 'O':
o << "~|";
break;
case 'r':
o << ">>";
break;
case 'X':
o << "~^";
break;
}
o << "(";
right_->dump(o);
@@ -569,9 +619,20 @@ void NetEBinary::dump(ostream&o) const
void NetEConcat::dump(ostream&o) const
{
o << "{" << *parms_[0];
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1)
o << ", " << *parms_[idx];
if (repeat_ != 1)
o << repeat_;
if (parms_[0])
o << "{" << *parms_[0];
else
o << "{";
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
if (parms_[idx])
o << ", " << *parms_[idx];
else
o << ", ";
}
o << "}";
}
@@ -608,9 +669,15 @@ void NetEMemory::dump(ostream&o) const
o << "]";
}
void NetEParam::dump(ostream&o) const
{
o << "<" << path_ << "." << name_ << ">";
}
void NetESignal::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Expression Node: " << name() << endl;
o << setw(ind) << "" << "Expression Node (NetESignal): " <<
name() << endl;
dump_node_pins(o, ind+4);
}
@@ -621,9 +688,29 @@ void NetETernary::dump(ostream&o) const
false_val_ << ")";
}
void NetEUFunc::dump(ostream&o) const
{
o << name() << "(";
assert(parms_.count() > 0);
parms_[0]->dump(o);
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
o << ", ";
parms_[idx]->dump(o);
}
o << ")";
}
void NetEUnary::dump(ostream&o) const
{
o << op_ << "(";
switch (op_) {
case 'N':
o << "~|";
break;
default:
o << op_;
break;
}
o << "(";
expr_->dump(o);
o << ")";
}
@@ -660,6 +747,15 @@ void Design::dump(ostream&o) const
}
}
o << "ELABORATED FUNCTION DEFINITIONS:" << endl;
{
map<string,NetFuncDef*>::const_iterator pp;
for (pp = funcs_.begin()
; pp != funcs_.end() ; pp ++) {
(*pp).second->dump(o, 0);
}
}
o << "ELABORATED TASK DEFINITIONS:" << endl;
{
map<string,NetTaskDef*>::const_iterator pp;
@@ -690,6 +786,50 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.48 1999/10/07 05:25:33 steve
* Add non-const bit select in l-value of assignment.
*
* Revision 1.47 1999/10/06 05:06:16 steve
* Move the rvalue into NetAssign_ common code.
*
* Revision 1.46 1999/10/05 06:19:46 steve
* Add support for reduction NOR.
*
* Revision 1.45 1999/09/30 02:43:01 steve
* Elaborate ~^ and ~| operators.
*
* Revision 1.44 1999/09/29 18:36:03 steve
* Full case support
*
* Revision 1.43 1999/09/21 00:13:40 steve
* Support parameters that reference other paramters.
*
* Revision 1.42 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.41 1999/09/19 01:06:36 steve
* dump the repeat count, if applicable.
*
* Revision 1.40 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.39 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.38 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.37 1999/09/01 20:46:19 steve
* Handle recursive functions and arbitrary function
* references to other functions, properly pass
* function parameters and save function results.
*
* Revision 1.36 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.35 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.34 1999/08/01 16:34:50 steve
* Parse and elaborate rise/fall/decay times
* for gates, and handle the rules for partial
+340
View File
@@ -0,0 +1,340 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: elab_expr.cc,v 1.6 1999/09/30 02:43:02 steve Exp $"
#endif
# include "pform.h"
# include "netlist.h"
/*
* Elaborate binary expressions. This involves elaborating the left
* and right sides, and creating one of a variety of different NetExpr
* types.
*/
NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
{
bool flag;
NetExpr*lp = left_->elaborate_expr(des, path);
NetExpr*rp = right_->elaborate_expr(des, path);
if ((lp == 0) || (rp == 0)) {
delete lp;
delete rp;
return 0;
}
/* If either expression can be evaluated ahead of time, then
do so. This can prove helpful later. */
{ NetExpr*tmp;
tmp = lp->eval_tree();
if (tmp) {
delete lp;
lp = tmp;
}
tmp = rp->eval_tree();
if (tmp) {
delete rp;
rp = tmp;
}
}
NetEBinary*tmp;
switch (op_) {
default:
tmp = new NetEBinary(op_, lp, rp);
tmp->set_line(*this);
break;
case 'a':
case 'o':
tmp = new NetEBLogic(op_, lp, rp);
tmp->set_line(*this);
break;
case 'l':
case 'r':
tmp = new NetEBShift(op_, lp, rp);
tmp->set_line(*this);
break;
case '^':
case '&':
case '|':
case 'O':
case 'X':
tmp = new NetEBBits(op_, lp, rp);
tmp->set_line(*this);
break;
case '+':
case '-':
tmp = new NetEBAdd(op_, lp, rp);
tmp->set_line(*this);
break;
case 'e': /* == */
case 'E': /* === */
case 'n': /* != */
case 'N': /* !== */
case 'L': /* <= */
case 'G': /* >= */
case '<':
case '>':
tmp = new NetEBComp(op_, lp, rp);
tmp->set_line(*this);
flag = tmp->set_width(1);
if (flag == false) {
cerr << get_line() << ": internal error: "
"expression bit width of comparison != 1." << endl;
des->errors += 1;
}
break;
}
return tmp;
}
NetESFunc* PECallFunction::elaborate_sfunc_(Design*des, const string&path) const
{
cerr << get_line() << ": sorry: system functions not supported."
<< endl;
des->errors += 1;
return 0;
}
NetExpr* PECallFunction::elaborate_expr(Design*des, const string&path) const
{
if (name_[0] == '$')
return elaborate_sfunc_(des, path);
string myname = path+"."+name_;
NetFuncDef*def = des->find_function(path, name_);
if (def == 0) {
cerr << get_line() << ": error: No function " << name_ <<
" in this context (" << path << ")." << endl;
des->errors += 1;
return 0;
}
assert(def);
svector<NetExpr*> parms (parms_.count());
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
NetExpr*tmp = parms_[idx]->elaborate_expr(des, myname);
parms[idx] = tmp;
}
/* Look for the return value signal for the called function in
the context of the function definition, not my context. */
NetNet*res = des->find_signal(def->name(), name_);
if (res == 0) {
cerr << get_line() << ": internal error: Unable to locate "
"function return value for " << name_ << " in " <<
def->name() << "." << endl;
des->errors += 1;
return 0;
}
assert(res);
NetESignal*eres = new NetESignal(res);
assert(eres);
des->add_node(eres);
NetEUFunc*func = new NetEUFunc(def, eres, parms);
return func;
}
NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const
{
// System identifiers show up in the netlist as identifiers.
if (text_[0] == '$')
return new NetEIdent(text_, 64);
string name = path+"."+text_;
// If the identifier name is a parameter name, then return
// a reference to the parameter expression.
if (const NetExpr*ex = des->find_parameter(path, text_)) {
NetExpr*tmp;
if (dynamic_cast<const NetExpr*>(ex))
tmp = ex->dup_expr();
else
tmp = new NetEParam(des, path, text_);
tmp->set_line(*this);
return tmp;
}
// If the identifier names a signal (a register or wire)
// then create a NetESignal node to handle it.
if (NetNet*net = des->find_signal(path, text_)) {
// If this is a part select of a signal, then make a new
// temporary signal that is connected to just the
// selected bits.
if (lsb_) {
assert(msb_);
verinum*lsn = lsb_->eval_const(des, path);
verinum*msn = msb_->eval_const(des, path);
if ((lsn == 0) || (msn == 0)) {
cerr << get_line() << ": error: "
"Part select expresions must be "
"constant expressions." << endl;
des->errors += 1;
return 0;
}
assert(lsn);
assert(msn);
unsigned long lsv = lsn->as_ulong();
unsigned long msv = msn->as_ulong();
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
assert(wid <= net->pin_count());
assert(net->sb_to_idx(msv) >= net->sb_to_idx(lsv));
string tname = des->local_symbol(path);
NetESignal*tmp = new NetESignal(tname, wid);
tmp->set_line(*this);
// Connect the pins from the lsb up to the msb.
unsigned off = net->sb_to_idx(lsv);
for (unsigned idx = 0 ; idx < wid ; idx += 1)
connect(tmp->pin(idx), net->pin(idx+off));
des->add_node(tmp);
return tmp;
}
// If the bit select is constant, then treat it similar
// to the part select, so that I save the effort of
// making a mux part in the netlist.
verinum*msn;
if (msb_ && (msn = msb_->eval_const(des, path))) {
assert(idx_ == 0);
unsigned long msv = msn->as_ulong();
string tname = des->local_symbol(path);
NetESignal*tmp = new NetESignal(tname, 1);
tmp->set_line(*this);
connect(tmp->pin(0), net->pin(msv));
des->add_node(tmp);
return tmp;
}
NetESignal*node = new NetESignal(net);
des->add_node(node);
assert(idx_ == 0);
// Non-constant bit select? punt and make a subsignal
// device to mux the bit in the net.
if (msb_) {
NetExpr*ex = msb_->elaborate_expr(des, path);
NetESubSignal*ss = new NetESubSignal(node, ex);
ss->set_line(*this);
return ss;
}
// All else fails, return the signal itself as the
// expression.
assert(msb_ == 0);
return node;
}
// If the identifier names a memory, then this is a
// memory reference and I must generate a NetEMemory
// object to handle it.
if (NetMemory*mem = des->find_memory(name)) {
assert(msb_ != 0);
assert(lsb_ == 0);
assert(idx_ == 0);
NetExpr*i = msb_->elaborate_expr(des, path);
if (i == 0) {
cerr << get_line() << ": error: Unable to exaborate "
"index expression `" << *msb_ << "'" << endl;
des->errors += 1;
return 0;
}
NetEMemory*node = new NetEMemory(mem, i);
node->set_line(*this);
return node;
}
// I cannot interpret this identifier. Error message.
cerr << get_line() << ": error: Unable to bind wire/reg/memory "
"`" << path << "." << text_ << "'" << endl;
des->errors += 1;
return 0;
}
/*
* Elaborate the Ternary operator. I know that the expressions were
* parsed so I can presume that they exist, and call elaboration
* methods. If any elaboration fails, then give up and return 0.
*/
NetExpr*PETernary::elaborate_expr(Design*des, const string&path) const
{
assert(expr_);
assert(tru_);
assert(fal_);
NetExpr*con = expr_->elaborate_expr(des, path);
if (con == 0)
return 0;
NetExpr*tru = tru_->elaborate_expr(des, path);
if (tru == 0) {
delete con;
return 0;
}
NetExpr*fal = fal_->elaborate_expr(des, path);
if (fal == 0) {
delete con;
delete tru;
return 0;
}
NetETernary*res = new NetETernary(con, tru, fal);
return res;
}
/*
* $Log: elab_expr.cc,v $
* Revision 1.6 1999/09/30 02:43:02 steve
* Elaborate ~^ and ~| operators.
*
* Revision 1.5 1999/09/30 00:48:49 steve
* Cope with errors during ternary operator elaboration.
*
* Revision 1.4 1999/09/29 22:57:10 steve
* Move code to elab_expr.cc
*
* Revision 1.3 1999/09/25 02:57:30 steve
* Parse system function calls.
*
* Revision 1.2 1999/09/21 00:13:40 steve
* Support parameters that reference other paramters.
*
* Revision 1.1 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
*/
+1019 -379
View File
File diff suppressed because it is too large Load Diff
+84 -25
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: emit.cc,v 1.18 1999/07/17 19:50:59 steve Exp $"
#ident "$Id: emit.cc,v 1.23 1999/09/22 16:57:23 steve Exp $"
#endif
/*
@@ -45,6 +45,11 @@ void NetUDP::emit_node(ostream&o, struct target_t*tgt) const
tgt->udp(o, this);
}
void NetAddSub::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->lpm_add_sub(o, this);
}
void NetAssign::emit_node(ostream&o, struct target_t*tgt) const
{
tgt->net_assign(o, this);
@@ -70,54 +75,68 @@ void NetBUFZ::emit_node(ostream&o, struct target_t*tgt) const
tgt->bufz(o, this);
}
void NetProcTop::emit(ostream&o, struct target_t*tgt) const
bool NetProcTop::emit(ostream&o, struct target_t*tgt) const
{
tgt->process(o, this);
return tgt->process(o, this);
}
void NetProc::emit_proc(ostream&o, struct target_t*tgt) const
bool NetProc::emit_proc(ostream&o, struct target_t*tgt) const
{
cerr << "EMIT: Proc type? " << typeid(*this).name() << endl;
return false;
}
void NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssign::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign(o, this);
return true;
}
void NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssignNB::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign_nb(o, this);
return true;
}
void NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssignMem::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_assign_mem(o, this);
return true;
}
void NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
bool NetAssignMemNB::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_block(o, this);
tgt->proc_assign_mem_nb(o, this);
return true;
}
void NetCase::emit_proc(ostream&o, struct target_t*tgt) const
bool NetBlock::emit_proc(ostream&o, struct target_t*tgt) const
{
return tgt->proc_block(o, this);
}
bool NetCase::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_case(o, this);
return true;
}
void NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
bool NetCondit::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_condit(o, this);
return true;
}
void NetForever::emit_proc(ostream&o, struct target_t*tgt) const
bool NetForever::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_forever(o, this);
return true;
}
void NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
bool NetPDelay::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_delay(o, this);
return true;
}
void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
@@ -125,9 +144,10 @@ void NetPDelay::emit_proc_recurse(ostream&o, struct target_t*tgt) const
if (statement_) statement_->emit_proc(o, tgt);
}
void NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
bool NetPEvent::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_event(o, this);
return true;
}
void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
@@ -135,24 +155,28 @@ void NetPEvent::emit_proc_recurse(ostream&o, struct target_t*tgt) const
if (statement_) statement_->emit_proc(o, tgt);
}
void NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
bool NetRepeat::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_repeat(o, this);
return true;
}
void NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
bool NetSTask::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_stask(o, this);
return true;
}
void NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
bool NetUTask::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_utask(o, this);
return true;
}
void NetWhile::emit_proc(ostream&o, struct target_t*tgt) const
bool NetWhile::emit_proc(ostream&o, struct target_t*tgt) const
{
tgt->proc_while(o, this);
return true;
}
void NetBlock::emit_recurse(ostream&o, struct target_t*tgt) const
@@ -196,8 +220,9 @@ void NetWhile::emit_proc_recurse(ostream&o, struct target_t*tgt) const
proc_->emit_proc(o, tgt);
}
void Design::emit(ostream&o, struct target_t*tgt) const
bool Design::emit(ostream&o, struct target_t*tgt) const
{
bool rc = true;
tgt->start_design(o, this);
// emit signals
@@ -229,6 +254,14 @@ void Design::emit(ostream&o, struct target_t*tgt) const
}
// emit function definitions
{
map<string,NetFuncDef*>::const_iterator ta;
for (ta = funcs_.begin() ; ta != funcs_.end() ; ta ++) {
tgt->func_def(o, (*ta).second);
}
}
// emit task definitions
{
map<string,NetTaskDef*>::const_iterator ta;
@@ -239,9 +272,10 @@ void Design::emit(ostream&o, struct target_t*tgt) const
// emit the processes
for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_)
idx->emit(o, tgt);
rc = rc && idx->emit(o, tgt);
tgt->end_design(o, this);
return rc;
}
void NetEBinary::expr_scan(struct expr_scan_t*tgt) const
@@ -269,6 +303,17 @@ void NetEMemory::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_memory(this);
}
void NetEParam::expr_scan(struct expr_scan_t*tgt) const
{
cerr << get_line() << ":internal error: unexpected NetEParam."
<< endl;
}
void NetEUFunc::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_ufunc(this);
}
void NetESignal::expr_scan(struct expr_scan_t*tgt) const
{
tgt->expr_signal(this);
@@ -294,20 +339,34 @@ void NetEUnary::expr_scan(struct expr_scan_t*tgt) const
tgt->expr_unary(this);
}
void emit(ostream&o, const Design*des, const char*type)
bool emit(ostream&o, const Design*des, const char*type)
{
for (unsigned idx = 0 ; target_table[idx] ; idx += 1) {
const struct target*tgt = target_table[idx];
if (tgt->name == type) {
des->emit(o, tgt->meth);
return;
}
if (tgt->name == type)
return des->emit(o, tgt->meth);
}
}
/*
* $Log: emit.cc,v $
* Revision 1.23 1999/09/22 16:57:23 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.22 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.21 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.20 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.19 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.18 1999/07/17 19:50:59 steve
* netlist support for ternary operator.
*
+24 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: eval.cc,v 1.5 1999/08/06 04:05:28 steve Exp $"
#ident "$Id: eval.cc,v 1.8 1999/09/20 02:21:10 steve Exp $"
#endif
# include "PExpr.h"
@@ -56,11 +56,24 @@ verinum* PEBinary::eval_const(const Design*des, const string&path) const
return res;
}
/*
* Evaluate an identifier as a constant expression. This is only
* possible if the identifier is that of a parameter.
*/
verinum* PEIdent::eval_const(const Design*des, const string&path) const
{
assert(msb_ == 0);
const NetExpr*expr = des->find_parameter(path, text_);
if (expr == 0) return 0;
if (expr == 0)
return 0;
if (dynamic_cast<const NetEParam*>(expr)) {
cerr << get_line() << ": sorry: I cannot evaluate ``" <<
text_ << "'' in this context." << endl;
return 0;
}
const NetEConst*eval = dynamic_cast<const NetEConst*>(expr);
assert(eval);
return new verinum(eval->value());
@@ -79,6 +92,15 @@ verinum* PETernary::eval_const(const Design*, const string&) const
/*
* $Log: eval.cc,v $
* Revision 1.8 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.7 1999/09/18 01:52:48 steve
* Remove spurious message.
*
* Revision 1.6 1999/09/16 04:18:15 steve
* elaborate concatenation repeats.
*
* Revision 1.5 1999/08/06 04:05:28 steve
* Handle scope of parameters.
*
+254
View File
@@ -0,0 +1,254 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: eval_tree.cc,v 1.4 1999/09/23 03:56:57 steve Exp $"
#endif
# include "netlist.h"
NetExpr* NetExpr::eval_tree()
{
return 0;
}
/*
* Some of the derived classes can be evaluated by the compiler, this
* method provides the common aid of evaluating the parameter
* expressions.
*/
void NetEBinary::eval_sub_tree_()
{
NetExpr*tmp = left_->eval_tree();
if (tmp) {
delete left_;
left_ = tmp;
}
tmp = right_->eval_tree();
if (tmp){
delete right_;
right_ = tmp;
}
}
NetExpr* NetEBComp::eval_eqeq_()
{
NetEConst*l = dynamic_cast<NetEConst*>(left_);
if (l == 0) return 0;
NetEConst*r = dynamic_cast<NetEConst*>(right_);
if (r == 0) return 0;
const verinum&lv = l->value();
const verinum&rv = r->value();
if (lv.len() < rv.len())
return 0;
verinum result(verinum::V1, 1);
for (unsigned idx = 0 ; idx < lv.len(); idx += 1) {
if (lv[idx] != rv[idx])
result = verinum::V0;
}
return new NetEConst(result);
}
NetExpr* NetEBComp::eval_leeq_()
{
NetEConst*r = dynamic_cast<NetEConst*>(right_);
if (r == 0) return 0;
verinum rv = r->value();
/* Detect the case where the right side is greater that or
equal to the largest value the left side can possibly
have. */
unsigned long lv = (1 << left_->expr_width()) - 1;
if (lv <= rv.as_ulong()) {
verinum result(verinum::V1, 1);
return new NetEConst(result);
}
return 0;
}
NetExpr* NetEBComp::eval_tree()
{
eval_sub_tree_();
switch (op_) {
case 'e':
return eval_eqeq_();
case 'L':
return eval_leeq_();
default:
return 0;
}
}
NetExpr* NetEBLogic::eval_tree()
{
eval_sub_tree_();
return 0;
}
/*
* Evaluate the shift operator if possible. For this to work, both
* operands must be constant.
*/
NetExpr* NetEBShift::eval_tree()
{
eval_sub_tree_();
NetEConst*re = dynamic_cast<NetEConst*>(right_);
if (re == 0)
return 0;
NetEConst*le = dynamic_cast<NetEConst*>(left_);
if (le == 0)
return 0;
NetEConst*res;
verinum rv = re->value();
verinum lv = le->value();
if (rv.is_defined()) {
unsigned wid = expr_width();
unsigned shift = rv.as_ulong();
verinum nv (verinum::V0, wid);
if (op() == 'r')
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
nv.set(idx, lv[idx+shift]);
else
for (unsigned idx = 0 ; idx < (wid-shift) ; idx += 1)
nv.set(idx+shift, lv[idx]);
res = new NetEConst(nv);
} else {
verinum nv (verinum::Vx, expr_width());
res = new NetEConst(nv);
}
return res;
}
NetExpr* NetEConcat::eval_tree()
{
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
// Parameter not here? This is an error, but presumably
// already caught and we are here just to catch more.
if (parms_[idx] == 0)
continue;
// If this parameter is already a constant, all is well
// so go on.
if (dynamic_cast<NetEConst*>(parms_[idx]))
continue;
// Finally, try to evaluate the parameter expression
// that is here. If I succeed, reset the parameter to
// the evaluated value.
assert(parms_[idx]);
NetExpr*expr = parms_[idx]->eval_tree();
if (expr) {
delete parms_[idx];
parms_[idx] = expr;
}
}
unsigned gap = expr_width() / repeat_;
verinum val (verinum::Vx, repeat_ * gap);
// build up the result from least significant to most.
unsigned cur = 0;
for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) {
NetEConst*expr = dynamic_cast<NetEConst*>(parms_[idx-1]);
if (expr == 0)
return 0;
verinum tmp = expr->value();
for (unsigned bit = 0 ; bit < tmp.len() ; bit += 1, cur += 1)
for (unsigned rep = 0 ; rep < repeat_ ; rep += 1)
val.set(rep*gap+cur, tmp[bit]);
}
NetEConst*res = new NetEConst(val);
res->set_width(val.len());
return res;
}
NetExpr* NetEParam::eval_tree()
{
if (des_ == 0)
return 0;
const NetExpr*expr = des_->find_parameter(path_, name_);
assert(expr);
NetExpr*nexpr = expr->dup_expr();
assert(nexpr);
// If the parameter that I refer to is already evaluated, then
// return the constant value.
if (dynamic_cast<NetEConst*>(nexpr))
return nexpr;
// Try to evaluate the expression. If I cannot, then the
// expression is not a constant expression and I fail here.
NetExpr*res = nexpr->eval_tree();
if (res == 0) {
delete nexpr;
return 0;
}
// The result can be saved as the value of the parameter for
// future reference, and return a copy to the caller.
des_->set_parameter(path_+"."+name_, res);
return res->dup_expr();
}
/*
* $Log: eval_tree.cc,v $
* Revision 1.4 1999/09/23 03:56:57 steve
* Support shift operators.
*
* Revision 1.3 1999/09/23 00:21:54 steve
* Move set_width methods into a single file,
* Add the NetEBLogic class for logic expressions,
* Fix error setting with of && in if statements.
*
* Revision 1.2 1999/09/21 00:13:40 steve
* Support parameters that reference other paramters.
*
* Revision 1.1 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
*/
+5 -2
View File
@@ -19,12 +19,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: globals.h,v 1.1 1999/07/03 20:03:47 steve Exp $"
#ident "$Id: globals.h,v 1.2 1999/09/05 22:33:18 steve Exp $"
#endif
# include <stdio.h>
extern void reset_lexor(FILE*out, const char*ipath);
extern void reset_lexor(FILE*out, char*paths[]);
extern void define_macro(const char*name, const char*value);
/* These variables contain the include directories to be searched when
@@ -40,6 +40,9 @@ extern int yyparse();
/*
* $Log: globals.h,v $
* Revision 1.2 1999/09/05 22:33:18 steve
* Take multiple source files on the command line.
*
* Revision 1.1 1999/07/03 20:03:47 steve
* Add include path and line directives.
*
+63 -10
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.11 1999/07/25 00:03:13 steve Exp $"
#ident "$Id: lexor.lex,v 1.13 1999/09/16 00:49:05 steve Exp $"
#endif
# include <stdio.h>
@@ -60,6 +60,7 @@ struct include_stack_t {
struct include_stack_t*next;
};
static struct include_stack_t*file_queue = 0;
static struct include_stack_t*istack = 0;
static struct include_stack_t*standby = 0;
@@ -114,7 +115,7 @@ W [ \t\b\f]+
that follows it. when the directive ends, the do_include function
performs the include operation. */
^`include { BEGIN(PPINCLUDE); }
^{W}?`include { BEGIN(PPINCLUDE); }
<PPINCLUDE>\"[^\"]*\" { include_filename(); }
@@ -128,7 +129,7 @@ W [ \t\b\f]+
directive and the name, go into PPDEFINE mode and prepare to
collect the defined value. */
^`define{W}[a-zA-Z][a-zA-Z0-9_]*{W}? { BEGIN(PPDEFINE); def_start(); }
`define{W}[a-zA-Z][a-zA-Z0-9_]*{W}? { BEGIN(PPDEFINE); def_start(); }
<PPDEFINE>.*\n {
do_define();
@@ -137,7 +138,7 @@ W [ \t\b\f]+
BEGIN(0);
}
^`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
`undef{W}[a-zA-Z][a-zA-Z0-9_]*{W}?.* { def_undefine(); }
/* Detect conditional compilation directives, and parse them. If I
@@ -469,12 +470,18 @@ static void do_include()
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
}
/*
* The lexical analyzer calls this function when the current file
* ends. Here I pop the include stack and resume the previous file. If
* there is no previous file, then the main input is ended.
*/
static int yywrap()
{
int line_mask_flag = 0;
struct include_stack_t*isp = istack;
istack = isp->next;
/* Delete the current input buffers, and free the cell. */
yy_delete_buffer(YY_CURRENT_BUFFER);
if (isp->file) {
fclose(isp->file);
@@ -492,13 +499,41 @@ static int yywrap()
}
free(isp);
if (istack == 0)
return 1;
/* If I am out if include stack, the main input is
done. Look for another file to process in the input
queue. If none are there, give up. Otherwise, open the file
and continue parsing. */
if (istack == 0) {
if (file_queue == 0)
return 1;
istack = file_queue;
file_queue = file_queue->next;
istack->next = 0;
istack->lineno = 0;
istack->file = fopen(istack->path, "r");
if (istack->file == 0) {
perror(istack->path);
exit(1);
}
if (line_direct_flag)
fprintf(yyout, "#line \"%s\" 0\n", istack->path);
yyrestart(isp->file);
return 0;
}
/* Otherwise, resume the input buffer that is the new stack
top. If I need to print a line directive, do so. */
yy_switch_to_buffer(istack->yybs);
if (line_direct_flag && istack->path && !line_mask_flag)
fprintf(yyout, "#line \"%s\" %u\n", istack->path, istack->lineno);
return 0;
}
@@ -507,14 +542,16 @@ static int yywrap()
* opened, and the lexor is initialized. The include stack is cleared
* and ready to go.
*/
void reset_lexor(FILE*out, const char*path)
void reset_lexor(FILE*out, char*paths[])
{
unsigned idx;
struct include_stack_t*tail = 0;
struct include_stack_t*isp = malloc(sizeof(struct include_stack_t));
isp->path = strdup(path);
isp->file = fopen(path, "r");
isp->path = strdup(paths[0]);
isp->file = fopen(paths[0], "r");
isp->str = 0;
if (isp->file == 0) {
perror(path);
perror(paths[0]);
exit(1);
}
@@ -525,4 +562,20 @@ void reset_lexor(FILE*out, const char*path)
assert(istack == 0);
istack = isp;
isp->next = 0;
/* Now build up a queue of all the remaining file names, so
that yywrap can pull them when needed. */
file_queue = 0;
for (idx = 1 ; paths[idx] ; idx += 1) {
isp = malloc(sizeof(struct include_stack_t));
isp->path = strdup(paths[idx]);
isp->str = 0;
isp->next = 0;
if (tail)
tail->next = isp;
else
file_queue = isp;
tail = isp;
}
}
+11 -3
View File
@@ -17,7 +17,7 @@ const char COPYRIGHT[] =
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: main.c,v 1.2 1999/07/03 20:03:47 steve Exp $"
#ident "$Id: main.c,v 1.3 1999/09/05 22:33:18 steve Exp $"
#endif
const char NOTICE[] =
@@ -109,7 +109,7 @@ int main(int argc, char*argv[])
flag_errors += 1;
if (flag_errors) {
fprintf(stderr, "\nUsage: %s [-v][-L][-I<dir>][-D<def>] <file>\n"
fprintf(stderr, "\nUsage: %s [-v][-L][-I<dir>][-D<def>] <file>...\n"
" -D<def> - Predefine a value.\n"
" -I<dir> - Add an include file search directory\n"
" -L - Emit line number directives\n"
@@ -129,12 +129,20 @@ int main(int argc, char*argv[])
out = stdout;
}
reset_lexor(out, argv[optind]);
if (argv[optind] == 0) {
fprintf(stderr, "%s: No input files given.\n", argv[0]);
return 1;
}
reset_lexor(out, argv+optind);
return yyparse();
}
/*
* $Log: main.c,v $
* Revision 1.3 1999/09/05 22:33:18 steve
* Take multiple source files on the command line.
*
* Revision 1.2 1999/07/03 20:03:47 steve
* Add include path and line directives.
*
+50 -129
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: lexor.lex,v 1.33 1999/07/17 18:25:38 steve Exp $"
#ident "$Id: lexor.lex,v 1.36 1999/09/30 04:51:14 steve Exp $"
#endif
//# define YYSTYPE lexval
@@ -41,7 +41,7 @@ extern YYLTYPE yylloc;
static void reset_lexor();
static void line_directive();
static int check_identifier(const char*name);
extern int check_identifier(const char*str, int len);
static verinum*make_sized_binary(const char*txt);
static verinum*make_sized_dec(const char*txt);
static verinum*make_unsized_dec(const char*txt);
@@ -128,7 +128,7 @@ W [ \t\b\f\r]+
<UDPTABLE>[pPnN01\?\*\-] { return yytext[0]; }
[a-zA-Z_][a-zA-Z0-9$_]* {
int rc = check_identifier(yytext);
int rc = check_identifier(yytext, yyleng);
if (rc == IDENTIFIER)
yylval.text = strdup(yytext);
else
@@ -150,8 +150,11 @@ W [ \t\b\f\r]+
yylval.text = strdup(yytext);
return SYSTEM_IDENTIFIER; }
\.[a-zA-Z_][a-zA-Z0-9$_]* {
yylval.text = strdup(yytext+1);
\.{W}?[a-zA-Z_][a-zA-Z0-9$_]* {
char*cp = yytext+1;
while (! (isalpha(*cp) || (*cp == '_')))
cp += 1;
yylval.text = strdup(cp);
return PORTNAME; }
[0-9][0-9_]*[ \t]*\'d[ \t]*[0-9][0-9_]* {
@@ -305,118 +308,6 @@ void lex_end_table()
BEGIN(INITIAL);
}
static const struct { const char*name; int code; } key_table[] = {
{ "always", K_always },
{ "and", K_and },
{ "assign", K_assign },
{ "begin", K_begin },
{ "buf", K_buf },
{ "bufif0", K_bufif0 },
{ "bufif1", K_bufif1 },
{ "case", K_case },
{ "casex", K_casex },
{ "casez", K_casez },
{ "cmos", K_cmos },
{ "deassign", K_deassign },
{ "default", K_default },
{ "defparam", K_defparam },
{ "disable", K_disable },
{ "edge", K_edge },
{ "else", K_else },
{ "end", K_end },
{ "endcase", K_endcase },
{ "endfunction", K_endfunction },
{ "endmodule", K_endmodule },
{ "endprimitive", K_endprimitive },
{ "endspecify", K_endspecify },
{ "endtable", K_endtable },
{ "endtask", K_endtask },
{ "event", K_event },
{ "for", K_for },
{ "force", K_force },
{ "forever", K_forever },
{ "fork", K_fork },
{ "function", K_function },
{ "highz0", K_highz0 },
{ "highz1", K_highz1 },
{ "if", K_if },
{ "initial", K_initial },
{ "inout", K_inout },
{ "input", K_input },
{ "integer", K_integer },
{ "join", K_join },
{ "large", K_large },
{ "macromodule", K_macromodule },
{ "medium", K_medium },
{ "module", K_module },
{ "nand", K_nand },
{ "negedge", K_negedge },
{ "nmos", K_nmos },
{ "nor", K_nor },
{ "not", K_not },
{ "notif0", K_notif0 },
{ "notif1", K_notif1 },
{ "or", K_or },
{ "output", K_output },
{ "parameter", K_parameter },
{ "pmos", K_pmos },
{ "posedge", K_posedge },
{ "primitive", K_primitive },
{ "pull0", K_pull0 },
{ "pull1", K_pull1 },
{ "pulldown", K_pulldown },
{ "pullup", K_pullup },
{ "rcmos", K_rcmos },
{ "reg", K_reg },
{ "release", K_release },
{ "repeat", K_repeat },
{ "rnmos", K_rnmos },
{ "rpmos", K_rpmos },
{ "rtran", K_rtran },
{ "rtranif0", K_rtranif0 },
{ "rtranif1", K_rtranif1 },
{ "scalered", K_scalered },
{ "small", K_small },
{ "specify", K_specify },
{ "specparam", K_specparam },
{ "strong0", K_strong0 },
{ "strong1", K_strong1 },
{ "supply0", K_supply0 },
{ "supply1", K_supply1 },
{ "table", K_table },
{ "task", K_task },
{ "time", K_time },
{ "tran", K_tran },
{ "tranif0", K_tranif0 },
{ "tranif1", K_tranif1 },
{ "tri", K_tri },
{ "tri0", K_tri0 },
{ "tri1", K_tri1 },
{ "triand", K_triand },
{ "trior", K_trior },
{ "trireg", K_trireg },
{ "vectored", K_vectored },
{ "wait", K_wait },
{ "wand", K_wand },
{ "weak0", K_weak0 },
{ "weak1", K_weak1 },
{ "while", K_while },
{ "wire", K_wire },
{ "wor", K_wor },
{ "xnor", K_xnor },
{ "xor", K_xor },
{ 0, IDENTIFIER }
};
static int check_identifier(const char*name)
{
for (unsigned idx = 0 ; key_table[idx].name ; idx += 1)
if (strcmp(key_table[idx].name, name) == 0)
return key_table[idx].code;
return IDENTIFIER;
}
static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr)
{
assert(tolower(*ptr) == 'b');
@@ -540,47 +431,77 @@ static verinum*make_sized_octal(const char*txt)
ptr += 1;
assert(tolower(*ptr) == 'o');
/* We know from the size number how bit to make the verinom
array, so make it now. */
verinum::V*bits = new verinum::V[size];
/* skip white space between size and the base token. */
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
ptr += 1;
unsigned idx = 0;
/* Find the end of the digits. ptr already points to the start. */
char*eptr = ptr + strlen(ptr);
while ((eptr > ptr) && (idx < (size-3))) {
switch (*eptr) {
/* From the last digit and forward, build up the number, least
significant bit first. This loop will not get the last few
bits if the size is not a multiple of 3. */
unsigned idx = 0;
while ((eptr > ptr) && ((idx/3) < (size/3))) switch (*--eptr) {
case 'x': case 'X':
bits[idx++] = verinum::Vx;
bits[idx++] = verinum::Vx;
bits[idx++] = verinum::Vx;
break;
case 'z': case 'Z': case '?':
bits[idx++] = verinum::Vz;
bits[idx++] = verinum::Vz;
bits[idx++] = verinum::Vz;
break;
default: {
unsigned val = *eptr - '0';
bits[idx++] = (val&1)? verinum::V1 : verinum::V0;
bits[idx++] = (val&2)? verinum::V1 : verinum::V0;
bits[idx++] = (val&4)? verinum::V1 : verinum::V0;
}
}
eptr -= 1;
}
// zero extend octal numbers
while (idx < size) switch (ptr[1]) {
if ((eptr > ptr) && (idx < size)) switch (*--eptr) {
case 'x': case 'X':
bits[idx++] = verinum::Vx;
for ( ; idx < size ; idx += 1)
bits[idx] = verinum::Vx;
break;
case 'z': case 'Z': case '?':
bits[idx++] = verinum::Vz;
for ( ; idx < size ; idx += 1)
bits[idx] = verinum::Vz;
break;
default:
bits[idx++] = verinum::V0;
default: {
unsigned val = *eptr - '0';
for ( ; idx < size ; idx += 1) {
bits[idx] = (val&1)? verinum::V1 : verinum::V0;
val >>= 1;
}
break;
}
} else {
// zero extend octal numbers
while (idx < size) switch (ptr[1]) {
case 'x': case 'X':
bits[idx++] = verinum::Vx;
break;
case 'z': case 'Z': case '?':
bits[idx++] = verinum::Vz;
break;
default:
bits[idx++] = verinum::V0;
}
}
return new verinum(bits, size, true);
+230
View File
@@ -0,0 +1,230 @@
/* C code produced by gperf version 2.7 */
/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf > lexor_keyword.cc */
#include "parse_misc.h"
#include "parse.h"
#include <string.h>
#define TOTAL_KEYWORDS 99
#define MIN_WORD_LENGTH 2
#define MAX_WORD_LENGTH 12
#define MIN_HASH_VALUE 7
#define MAX_HASH_VALUE 239
/* maximum key range = 233, duplicates = 0 */
#ifdef __GNUC__
__inline
#endif
static unsigned int
keyword_hash (const char *str, int len)
{
static const unsigned char asso_values[] =
{
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 126, 66,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 31, 11, 81,
1, 1, 81, 26, 11, 51, 11, 21, 81, 81,
1, 46, 16, 240, 1, 1, 6, 11, 36, 46,
21, 16, 6, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240
};
int hval = len;
hval += asso_values[(unsigned char)str[len - 1]];
hval += asso_values[(unsigned char)str[0]];
hval += asso_values[(unsigned char)str[1]];
if (len > 2)
hval += asso_values[(unsigned char)str[2]];
return hval ;
}
int
check_identifier (const char *str, int len)
{
static const struct { const char *name; int tokenType; } wordlist[] =
{
{""}, {""}, {""}, {""}, {""}, {""}, {""},
{"end", K_end},
{""}, {""}, {""},
{"endcase", K_endcase},
{"endtable", K_endtable},
{"endmodule", K_endmodule},
{"rtran", K_rtran},
{"endfunction", K_endfunction},
{"endprimitive", K_endprimitive},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""},
{"endspecify", K_endspecify},
{"repeat", K_repeat},
{"endtask", K_endtask},
{""},
{"edge", K_edge},
{""}, {""},
{"negedge", K_negedge},
{"and", K_and},
{"nand", K_nand},
{""},
{"assign", K_assign},
{"specify", K_specify},
{"deassign", K_deassign},
{"tran", K_tran},
{"begin", K_begin},
{""}, {""}, {""}, {""},
{"event", K_event},
{"or", K_or},
{""},
{"nor", K_nor},
{""},
{"table", K_table},
{""}, {""},
{"reg", K_reg},
{"parameter", K_parameter},
{""}, {""},
{"disable", K_disable},
{"not", K_not},
{"task", K_task},
{"trior", K_trior},
{"triand", K_triand},
{"integer", K_integer},
{""}, {""}, {""}, {""},
{"posedge", K_posedge},
{"xor", K_xor},
{"xnor", K_xnor},
{""},
{"output", K_output},
{""}, {""},
{"primitive", K_primitive},
{"input", K_input},
{""},
{"strong1", K_strong1},
{"rtranif1", K_rtranif1},
{"wand", K_wand},
{""}, {""}, {""}, {""},
{"else", K_else},
{"rnmos", K_rnmos},
{"trireg", K_trireg},
{"release", K_release},
{""}, {""}, {""}, {""},
{"default", K_default},
{"wor", K_wor},
{""}, {""}, {""},
{"supply1", K_supply1},
{"function", K_function},
{"wire", K_wire},
{"rpmos", K_rpmos},
{""}, {""}, {""},
{"specparam", K_specparam},
{"inout", K_inout},
{""},
{"tranif1", K_tranif1},
{"tri", K_tri},
{"join", K_join},
{"while", K_while},
{""}, {""},
{"pulldown", K_pulldown},
{"case", K_case},
{"large", K_large},
{""}, {""},
{"scalered", K_scalered},
{""},
{"casez", K_casez},
{"notif1", K_notif1},
{""},
{"vectored", K_vectored},
{"tri1", K_tri1},
{""},
{"pullup", K_pullup},
{""},
{"for", K_for},
{"nmos", K_nmos},
{"force", K_force},
{"module", K_module},
{"forever", K_forever},
{""},
{"wait", K_wait},
{"casex", K_casex},
{""},
{"strong0", K_strong0},
{"rtranif0", K_rtranif0},
{"time", K_time},
{""}, {""}, {""}, {""},
{"pmos", K_pmos},
{"weak1", K_weak1},
{""}, {""}, {""},
{"fork", K_fork},
{""}, {""}, {""}, {""}, {""}, {""},
{"highz1", K_highz1},
{"supply0", K_supply0},
{""}, {""}, {""},
{"always", K_always},
{""}, {""}, {""},
{"rcmos", K_rcmos},
{"medium", K_medium},
{"tranif0", K_tranif0},
{"defparam", K_defparam},
{""}, {""},
{"bufif1", K_bufif1},
{""}, {""}, {""},
{"pull1", K_pull1},
{""}, {""}, {""}, {""}, {""},
{"notif0", K_notif0},
{""},
{"buf", K_buf},
{"tri0", K_tri0},
{""}, {""},
{"initial", K_initial},
{""}, {""}, {""}, {""}, {""}, {""}, {""},
{"small", K_small},
{""}, {""}, {""}, {""}, {""},
{"macromodule", K_macromodule},
{""}, {""}, {""},
{"weak0", K_weak0},
{""}, {""}, {""},
{"cmos", K_cmos},
{""},
{"if", K_if},
{""}, {""}, {""}, {""},
{"highz0", K_highz0},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""}, {""}, {""},
{"bufif0", K_bufif0},
{""}, {""}, {""},
{"pull0", K_pull0}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
int key = keyword_hash (str, len);
if (key <= MAX_HASH_VALUE && key >= 0)
{
const char *s = wordlist[key].name;
if (*str == *s && !strcmp (str + 1, s + 1))
return wordlist[key].tokenType;
}
}
return IDENTIFIER;
}
+112
View File
@@ -0,0 +1,112 @@
%{
/* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf */
#include "parse_misc.h"
#include "parse.h"
#include <string.h>
%}
struct Keywords {
char *name;
int tokenType;
} Keywords;
%%
always, K_always
and, K_and
assign, K_assign
begin, K_begin
buf, K_buf
bufif0, K_bufif0
bufif1, K_bufif1
case, K_case
casex, K_casex
casez, K_casez
cmos, K_cmos
deassign, K_deassign
default, K_default
defparam, K_defparam
disable, K_disable
edge, K_edge
else, K_else
end, K_end
endcase, K_endcase
endfunction, K_endfunction
endmodule, K_endmodule
endprimitive, K_endprimitive
endspecify, K_endspecify
endtable, K_endtable
endtask, K_endtask
event, K_event
for, K_for
force, K_force
forever, K_forever
fork, K_fork
function, K_function
highz0, K_highz0
highz1, K_highz1
if, K_if
initial, K_initial
inout, K_inout
input, K_input
integer, K_integer
join, K_join
large, K_large
macromodule, K_macromodule
medium, K_medium
module, K_module
nand, K_nand
negedge, K_negedge
nmos, K_nmos
nor, K_nor
not, K_not
notif0, K_notif0
notif1, K_notif1
or, K_or
output, K_output
parameter, K_parameter
pmos, K_pmos
posedge, K_posedge
primitive, K_primitive
pull0, K_pull0
pull1, K_pull1
pulldown, K_pulldown
pullup, K_pullup
rcmos, K_rcmos
reg, K_reg
release, K_release
repeat, K_repeat
rnmos, K_rnmos
rpmos, K_rpmos
rtran, K_rtran
rtranif0, K_rtranif0
rtranif1, K_rtranif1
scalered, K_scalered
small, K_small
specify, K_specify
specparam, K_specparam
strong0, K_strong0
strong1, K_strong1
supply0, K_supply0
supply1, K_supply1
table, K_table
task, K_task
time, K_time
tran, K_tran
tranif0, K_tranif0
tranif1, K_tranif1
tri, K_tri
tri0, K_tri0
tri1, K_tri1
triand, K_triand
trior, K_trior
trireg, K_trireg
vectored, K_vectored
wait, K_wait
wand, K_wand
weak0, K_weak0
weak1, K_weak1
while, K_while
wire, K_wire
wor, K_wor
xnor, K_xnor
xor, K_xor
+12 -4
View File
@@ -19,7 +19,7 @@ const char COPYRIGHT[] =
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: main.cc,v 1.22 1999/08/03 04:14:49 steve Exp $"
#ident "$Id: main.cc,v 1.23 1999/09/22 16:57:23 steve Exp $"
#endif
const char NOTICE[] =
@@ -75,7 +75,6 @@ static void parm_to_flagmap(const string&flag)
extern Design* elaborate(const map<string,Module*>&modules,
const map<string,PUdp*>&primitives,
const string&root);
extern void emit(ostream&o, const Design*, const char*);
extern void cprop(Design*des);
extern void propinit(Design*des);
@@ -252,6 +251,7 @@ int main(int argc, char*argv[])
}
bool emit_rc;
if (out_path) {
ofstream out;
out.open(out_path);
@@ -261,10 +261,15 @@ int main(int argc, char*argv[])
return 1;
}
emit(out, des, target);
emit_rc = emit(out, des, target);
} else {
emit(cout, des, target);
emit_rc = emit(cout, des, target);
}
if (!emit_rc) {
cerr << "internal error: Code generation had errors." << endl;
return 1;
}
return 0;
@@ -272,6 +277,9 @@ int main(int argc, char*argv[])
/*
* $Log: main.cc,v $
* Revision 1.23 1999/09/22 16:57:23 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.22 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
+510 -272
View File
File diff suppressed because it is too large Load Diff
+424 -76
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: netlist.h,v 1.55 1999/08/06 04:05:28 steve Exp $"
#ident "$Id: netlist.h,v 1.78 1999/10/07 05:25:34 steve Exp $"
#endif
/*
@@ -40,6 +40,7 @@ class NetNode;
class NetProc;
class NetProcTop;
class NetExpr;
class NetESignal;
class ostream;
@@ -169,8 +170,8 @@ class NetObj {
bool test_mark() const { return mark_; }
void set_mark(bool flag=true) { mark_ = flag; }
Link&pin(unsigned idx) { return pins_[idx]; }
const Link&pin(unsigned idx) const { return pins_[idx]; }
Link&pin(unsigned idx);
const Link&pin(unsigned idx) const;
void dump_node_pins(ostream&, unsigned) const;
void dump_obj_attr(ostream&, unsigned) const;
@@ -219,7 +220,8 @@ class NetNode : public NetObj {
*
* Note that a net of any sort has exactly one pin. The pins feature
* of the NetObj class is used to make a set of identical wires, in
* order to support ranges, or busses.
* order to support ranges, or busses. When dealing with vectors,
* pin(0) is always the least significant bit.
*/
class NetNet : public NetObj, public LineInfo {
@@ -242,15 +244,17 @@ class NetNet : public NetObj, public LineInfo {
PortType port_type() const { return port_type_; }
void port_type(PortType t) { port_type_ = t; }
/* These methods return the msb and lsb indices for the most
significant and least significant bits. These are signed
longs, and may be different from pin numbers. For example,
reg [1:8] has 8 bits, msb==1 and lsb==8. */
long msb() const { return msb_; }
long lsb() const { return lsb_; }
unsigned sb_to_idx(long sb) const
{ if (msb_ >= lsb_)
return sb - lsb_;
else
return lsb_ - sb;
}
/* This method converts a signed index (the type that might be
found in the verilog source) to a pin number. It accounts
for variation in the definition of the reg/wire/whatever. */
unsigned sb_to_idx(long sb) const;
bool local_flag() const { return local_flag_; }
void local_flag(bool f) { local_flag_ = f; }
@@ -279,6 +283,36 @@ class NetNet : public NetObj, public LineInfo {
verinum::V*ivalue_;
};
/*
* This class implements the LPM_ADD_SUB component as described in the
* EDIF LPM Version 2 1 0 standard. It is used as a structural
* implementation of the + and - operators.
*/
class NetAddSub : public NetNode {
public:
NetAddSub(const string&n, unsigned width);
~NetAddSub();
// Get the width of the device (that is, the width of the
// operands and results.)
unsigned width() const;
NetObj::Link& pin_Aclr();
NetObj::Link& pin_Add_Sub();
NetObj::Link& pin_Clock();
NetObj::Link& pin_Cin();
NetObj::Link& pin_Cout();
NetObj::Link& pin_Overflow();
NetObj::Link& pin_DataA(unsigned idx);
NetObj::Link& pin_DataB(unsigned idx);
NetObj::Link& pin_Result(unsigned idx);
virtual void dump_node(ostream&, unsigned ind) const;
virtual void emit_node(ostream&, struct target_t*) const;
};
/*
* This class represents the declared memory object. The parser
* creates one of these for each declared memory in the elaborated
@@ -330,7 +364,7 @@ class NetMemory {
*/
class NetExpr : public LineInfo {
public:
explicit NetExpr(unsigned w =0) : width_(w) { }
explicit NetExpr(unsigned w =0);
virtual ~NetExpr() =0;
virtual void expr_scan(struct expr_scan_t*) const =0;
@@ -438,7 +472,7 @@ class NetLogic : public NetNode {
* expand it out any further then this in the netlist, as this can be
* used to represent target device primitives.
*
* The UDP can be combinational or sequential. The sequentianl UDP
* The UDP can be combinational or sequential. The sequential UDP
* includes the current output in the truth table, and supports edges,
* whereas the combinational does not and is entirely level sensitive.
* In any case, pin 0 is an output, and all the remaining pins are
@@ -549,13 +583,16 @@ class NetUDP : public NetNode {
* linked into the netlist. However, elaborating a process may cause
* special nodes to be created to handle things like events.
*/
class NetProc {
class NetProc : public LineInfo {
public:
explicit NetProc() : next_(0) { }
explicit NetProc();
virtual ~NetProc();
virtual void emit_proc(ostream&, struct target_t*) const;
// This method is called to emit the statement to the
// target. The target returns true if OK, false for errors.
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
@@ -570,33 +607,51 @@ class NetProc {
* lvalue object and represents the elaborated lvalue. Thus, this
* appears as a procedural statement AND a structural node. The
* LineInfo is the location of the assignment statement in the source.
*
* NOTE: The elaborator will make an effort to match the width of the
* r-value to the with of the assign node, but targets and functions
* should know that this is not a guarantee.
*/
class NetAssign_ : public NetProc, public NetNode, public LineInfo {
class NetAssign_ : public NetProc, public NetNode {
public:
// This is the (procedural) value that is to be assigned when
// the assignment is executed.
NetExpr*rval();
const NetExpr*rval() const;
// If this expression exists, then only a single bit is to be
// set from the rval, and the value of this expression selects
// the pin that gets the value.
const NetExpr*bmux() const;
protected:
NetAssign_(const string&n, unsigned w);
virtual ~NetAssign_() =0;
void set_rval(NetExpr*);
void set_bmux(NetExpr*);
private:
NetExpr*rval_;
NetExpr*bmux_;
};
class NetAssign : public NetAssign_ {
public:
explicit NetAssign(const string&, Design*des, unsigned w, NetExpr*rv);
explicit NetAssign(const string&, Design*des, unsigned w,
NetExpr*mux, NetExpr*rv);
~NetAssign();
NetExpr*rval() { return rval_; }
const NetExpr*rval() const { return rval_; }
void find_lval_range(const NetNet*&net, unsigned&msb,
unsigned&lsb) const;
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void emit_node(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual void dump_node(ostream&, unsigned ind) const;
private:
NetExpr* rval_;
};
/*
@@ -609,48 +664,61 @@ class NetAssignNB : public NetAssign_ {
NetExpr*mux, NetExpr*rv);
~NetAssignNB();
// This is the (procedural) value that is to be assigned when
// the assignment is executed.
const NetExpr*rval() const { return rval_; }
// If this expression exists, then only a single bit is to be
// set from the rval, and the value of this expression selects
// the pin that gets the value.
const NetExpr*bmux() const { return bmux_; }
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void emit_node(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual void dump_node(ostream&, unsigned ind) const;
private:
NetExpr* rval_;
NetExpr* bmux_;
};
/*
* Assignment to memory is handled separately because memory is
* not a node.
* not a node. There are blocking and non-blocking variants, just like
* regular assign, and the NetAssignMem_ base class takes care of all
* the common stuff.
*/
class NetAssignMem : public NetProc, public LineInfo {
class NetAssignMem_ : public NetProc {
public:
explicit NetAssignMem(NetMemory*, NetExpr*idx, NetExpr*rv);
~NetAssignMem();
explicit NetAssignMem_(NetMemory*, NetExpr*idx, NetExpr*rv);
~NetAssignMem_();
const NetMemory*memory()const { return mem_; }
const NetExpr*index()const { return index_; }
const NetExpr*rval()const { return rval_; }
virtual void emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
NetMemory*mem_;
NetExpr* index_;
NetExpr* rval_;
};
class NetAssignMem : public NetAssignMem_ {
public:
explicit NetAssignMem(NetMemory*, NetExpr*idx, NetExpr*rv);
~NetAssignMem();
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
};
class NetAssignMemNB : public NetAssignMem_ {
public:
explicit NetAssignMemNB(NetMemory*, NetExpr*idx, NetExpr*rv);
~NetAssignMemNB();
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
};
/* A block is stuff line begin-end blocks, that contain and ordered
list of NetProc statements.
@@ -670,7 +738,7 @@ class NetBlock : public NetProc {
void append(NetProc*);
void emit_recurse(ostream&, struct target_t*) const;
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
@@ -679,29 +747,40 @@ class NetBlock : public NetProc {
NetProc*last_;
};
/* A CASE statement in the verilog source leads, eventually, to one of
these. This is different from a simple conditional because of the
way the comparisons are performed. Also, it is likely that the
target may be able to optimize differently. */
/*
* A CASE statement in the verilog source leads, eventually, to one of
* these. This is different from a simple conditional because of the
* way the comparisons are performed. Also, it is likely that the
* target may be able to optimize differently.
*
* Case cane be one of three types:
* EQ -- All bits must exactly match
* EQZ -- z bits are don't care
* EQX -- x and z bits are don't care.
*/
class NetCase : public NetProc {
public:
NetCase(NetExpr*ex, unsigned cnt);
enum TYPE { EQ, EQX, EQZ };
NetCase(TYPE c, NetExpr*ex, unsigned cnt);
~NetCase();
void set_case(unsigned idx, NetExpr*ex, NetProc*st);
TYPE type() const;
const NetExpr*expr() const { return expr_; }
unsigned nitems() const { return nitems_; }
const NetExpr*expr(unsigned idx) const { return items_[idx].guard;}
const NetProc*stat(unsigned idx) const { return items_[idx].statement; }
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
TYPE type_;
struct Item {
NetExpr*guard;
NetProc*statement;
@@ -730,7 +809,7 @@ class NetCondit : public NetProc {
void emit_recurse_if(ostream&, struct target_t*) const;
void emit_recurse_else(ostream&, struct target_t*) const;
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
@@ -751,13 +830,41 @@ class NetForever : public NetProc {
void emit_recurse(ostream&, struct target_t*) const;
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
NetProc*statement_;
};
/*
* A funciton definition is elaborated just like a task, though by now
* it is certain that the first parameter (a phantom parameter) is the
* output and all the remaining parameters are the inputs. This makes
* for easy code generation in targets that support behavioral descriptions.
*/
class NetFuncDef {
public:
NetFuncDef(const string&, const svector<NetNet*>&po);
~NetFuncDef();
void set_proc(NetProc*st);
const string& name() const;
const NetProc*proc() const;
unsigned port_count() const;
const NetNet*port(unsigned idx) const;
virtual void dump(ostream&, unsigned ind) const;
private:
string name_;
NetProc*statement_;
svector<NetNet*>ports_;
};
class NetPDelay : public NetProc {
public:
@@ -766,7 +873,7 @@ class NetPDelay : public NetProc {
unsigned long delay() const { return delay_; }
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
void emit_proc_recurse(ostream&, struct target_t*) const;
@@ -796,7 +903,7 @@ class NetPEvent : public NetProc, public sref_back<NetPEvent,NetNEvent> {
NetProc* statement();
const NetProc* statement() const;
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
void emit_proc_recurse(ostream&, struct target_t*) const;
@@ -846,7 +953,7 @@ class NetRepeat : public NetProc {
const NetExpr*expr() const;
void emit_recurse(ostream&, struct target_t*) const;
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
@@ -872,7 +979,7 @@ class NetSTask : public NetProc {
const NetExpr* parm(unsigned idx) const;
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
@@ -888,9 +995,11 @@ class NetSTask : public NetProc {
class NetTaskDef {
public:
NetTaskDef(const string&n, NetProc*p, const svector<NetNet*>&po);
NetTaskDef(const string&n, const svector<NetNet*>&po);
~NetTaskDef();
void set_proc(NetProc*p);
const string& name() const { return name_; }
const NetProc*proc() const { return proc_; }
@@ -910,7 +1019,48 @@ class NetTaskDef {
};
/*
* A call to a user defined task is elaborated into this object.
* This node represents a function call in an expression. The object
* contains a pointer to the function definition, which is used to
* locate the value register and input expressions.
*
* The NetNet parameter to the constructor is the *register* NetNet
* that receives the result of the function, and the NetExpr list is
* the paraneters passed to the function.
*/
class NetEUFunc : public NetExpr {
public:
NetEUFunc(NetFuncDef*, NetESignal*, svector<NetExpr*>&);
~NetEUFunc();
const string& name() const;
const NetESignal*result() const;
unsigned parm_count() const;
const NetExpr* parm(unsigned idx) const;
const NetFuncDef* definition() const;
virtual bool set_width(unsigned);
virtual void dump(ostream&) const;
virtual void expr_scan(struct expr_scan_t*) const;
virtual NetEUFunc*dup_expr() const;
private:
NetFuncDef*func_;
NetESignal*result_;
svector<NetExpr*> parms_;
private: // not implemented
NetEUFunc(const NetEUFunc&);
NetEUFunc& operator= (const NetEUFunc&);
};
/*
* A call to a user defined task is elaborated into this object. This
* contains a pointer to the elaborated task definition, but is a
* NetProc object so that it can be linked into statements.
*/
class NetUTask : public NetProc {
@@ -920,7 +1070,7 @@ class NetUTask : public NetProc {
const string& name() const { return task_->name(); }
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
@@ -942,7 +1092,7 @@ class NetWhile : public NetProc {
void emit_proc_recurse(ostream&, struct target_t*) const;
virtual void emit_proc(ostream&, struct target_t*) const;
virtual bool emit_proc(ostream&, struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
@@ -951,9 +1101,11 @@ class NetWhile : public NetProc {
};
/* The is the top of any process. It carries the type (initial or
always) and a pointer to the statement, probably a block, that
makes up the process. */
/*
* The is the top of any process. It carries the type (initial or
* always) and a pointer to the statement, probably a block, that
* makes up the process.
*/
class NetProcTop : public LineInfo {
public:
@@ -967,7 +1119,7 @@ class NetProcTop : public LineInfo {
const NetProc*statement() const;
void dump(ostream&, unsigned ind) const;
void emit(ostream&, struct target_t*tgt) const;
bool emit(ostream&, struct target_t*tgt) const;
private:
const Type type_;
@@ -1000,8 +1152,10 @@ class NetProcTop : public LineInfo {
* N -- Case inequality (!==)
* a -- Logical AND (&&)
* o -- Logical OR (||)
* O -- Bit-wise NOR
* l -- Left shift (<<)
* r -- Right shift (>>)
* X -- Bitwise exclusive NOR (~^)
*/
class NetEBinary : public NetExpr {
@@ -1016,22 +1170,17 @@ class NetEBinary : public NetExpr {
virtual bool set_width(unsigned w);
// If both of my subexpressions are constants, then I can
// probably evaluate this part of the expression at compile
// time.
virtual NetExpr* eval_tree();
virtual NetEBinary* dup_expr() const;
virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const;
NetExpr*eval_eqeq();
protected:
char op_;
NetExpr* left_;
NetExpr* right_;
virtual void eval_sub_tree_();
};
/*
@@ -1061,6 +1210,8 @@ class NetEBAdd : public NetEBinary {
* ^ -- Bit-wise exclusive OR
* & -- Bit-wise AND
* | -- Bit-wise OR
* O -- Bit-wise NOR
* X -- Bit-wise XNOR (~^)
*/
class NetEBBits : public NetEBinary {
@@ -1092,8 +1243,53 @@ class NetEBComp : public NetEBinary {
~NetEBComp();
virtual bool set_width(unsigned w);
virtual NetExpr* eval_tree();
private:
NetExpr*eval_eqeq_();
NetExpr*eval_leeq_();
};
/*
* The binary logical operators are those that return boolean
* results. The supported operators are:
*
* a -- Logical AND (&&)
*/
class NetEBLogic : public NetEBinary {
public:
NetEBLogic(char op, NetExpr*l, NetExpr*r);
~NetEBLogic();
virtual bool set_width(unsigned w);
virtual NetExpr* eval_tree();
private:
};
/*
* The binary logical operators are those that return boolean
* results. The supported operators are:
*
* l -- left shift (<<)
* r -- right shift (>>)
*/
class NetEBShift : public NetEBinary {
public:
NetEBShift(char op, NetExpr*l, NetExpr*r);
~NetEBShift();
virtual bool set_width(unsigned w);
virtual NetExpr* eval_tree();
private:
};
/*
* This expression node supports the concat expression. This is an
* operator that just glues the results of many expressions into a
@@ -1106,29 +1302,31 @@ class NetEBComp : public NetEBinary {
class NetEConcat : public NetExpr {
public:
NetEConcat(unsigned cnt);
NetEConcat(unsigned cnt, unsigned repeat =1);
~NetEConcat();
// Manipulate the parameters.
void set(unsigned idx, NetExpr*e);
unsigned repeat() const { return repeat_; }
unsigned nparms() const { return parms_.count() ; }
NetExpr* parm(unsigned idx) const { return parms_[idx]; }
virtual bool set_width(unsigned w);
virtual NetEConcat* dup_expr() const;
virtual NetExpr* eval_tree();
virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const;
private:
svector<NetExpr*>parms_;
unsigned repeat_;
};
class NetEConst : public NetExpr {
public:
NetEConst(const verinum&val)
: NetExpr(val.len()), value_(val) { }
explicit NetEConst(const verinum&val);
~NetEConst();
const verinum&value() const { return value_; }
@@ -1143,6 +1341,67 @@ class NetEConst : public NetExpr {
verinum value_;
};
/*
* This clas is a placeholder for a parameter expression. When
* parameters are first created, an instance of this object is used to
* hold the place where the parameter exression goes. Then, when the
* parameters are resolved, these objects are removed.
*
* If the parameter object is created with a path and name, then the
* object represents a reference to a parameter that is known to exist.
*/
class NetEParam : public NetExpr {
public:
NetEParam();
NetEParam(class Design*des, const string&path, const string&name);
~NetEParam();
virtual bool set_width(unsigned w);
virtual void expr_scan(struct expr_scan_t*) const;
virtual NetExpr* eval_tree();
virtual NetEParam* dup_expr() const;
virtual void dump(ostream&) const;
private:
Design*des_;
string path_;
string name_;
};
/*
* This node represents a system function call in an expression. The
* object contains the name of the system function, which the backend
* uses to to VPI matching.
*/
class NetESFunc : public NetExpr {
public:
NetESFunc(const string&name, NetESignal*, svector<NetExpr*>&);
~NetESFunc();
const string& name() const;
const NetESignal*result() const;
unsigned parm_count() const;
const NetExpr* parm(unsigned idx) const;
virtual bool set_width(unsigned);
virtual void dump(ostream&) const;
virtual void expr_scan(struct expr_scan_t*) const;
virtual NetESFunc*dup_expr() const;
private:
string name_;
NetESignal*result_;
svector<NetExpr*> parms_;
private: // not implemented
NetESFunc(const NetESFunc&);
NetESFunc& operator= (const NetESFunc&);
};
/*
* This class represents the ternary (?:) operator. It has 3
* expressions, one of which is a condition used to select which of
@@ -1156,6 +1415,10 @@ class NetETernary : public NetExpr {
virtual bool set_width(unsigned w);
const NetExpr*cond_expr() const;
const NetExpr*true_expr() const;
const NetExpr*false_expr() const;
virtual NetETernary* dup_expr() const;
virtual void expr_scan(struct expr_scan_t*) const;
@@ -1185,8 +1448,7 @@ class NetETernary : public NetExpr {
class NetEUnary : public NetExpr {
public:
NetEUnary(char op, NetExpr*ex)
: NetExpr(ex->expr_width()), op_(op), expr_(ex) { }
NetEUnary(char op, NetExpr*ex);
~NetEUnary();
char op() const { return op_; }
@@ -1339,8 +1601,14 @@ class Design {
void add_memory(NetMemory*);
NetMemory* find_memory(const string&name);
// Functions
void add_function(const string&n, NetFuncDef*);
NetFuncDef* find_function(const string&path, const string&key);
NetFuncDef* find_function(const string&path);
// Tasks
void add_task(const string&n, NetTaskDef*);
NetTaskDef* find_task(const string&path, const string&name);
NetTaskDef* find_task(const string&key);
// NODES
@@ -1354,7 +1622,7 @@ class Design {
// Iterate over the design...
void dump(ostream&) const;
void functor(struct functor_t*);
void emit(ostream&, struct target_t*) const;
bool emit(ostream&, struct target_t*) const;
void clear_node_marks();
NetNode*find_node(bool (*test)(const NetNode*));
@@ -1379,6 +1647,9 @@ class Design {
map<string,NetMemory*> memories_;
// List the function definitions in the design.
map<string,NetFuncDef*> funcs_;
// List the task definitions in the design.
map<string,NetTaskDef*> tasks_;
@@ -1440,6 +1711,83 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.78 1999/10/07 05:25:34 steve
* Add non-const bit select in l-value of assignment.
*
* Revision 1.77 1999/10/06 05:06:16 steve
* Move the rvalue into NetAssign_ common code.
*
* Revision 1.76 1999/09/30 21:28:34 steve
* Handle mutual reference of tasks by elaborating
* task definitions in two passes, like functions.
*
* Revision 1.75 1999/09/30 02:43:02 steve
* Elaborate ~^ and ~| operators.
*
* Revision 1.74 1999/09/29 18:36:03 steve
* Full case support
*
* Revision 1.73 1999/09/28 03:11:30 steve
* Get the bit widths of unary operators that return one bit.
*
* Revision 1.72 1999/09/25 02:57:30 steve
* Parse system function calls.
*
* Revision 1.71 1999/09/23 03:56:57 steve
* Support shift operators.
*
* Revision 1.70 1999/09/23 00:21:55 steve
* Move set_width methods into a single file,
* Add the NetEBLogic class for logic expressions,
* Fix error setting with of && in if statements.
*
* Revision 1.69 1999/09/22 16:57:23 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.68 1999/09/21 00:13:40 steve
* Support parameters that reference other paramters.
*
* Revision 1.67 1999/09/20 02:21:10 steve
* Elaborate parameters in phases.
*
* Revision 1.66 1999/09/18 01:53:08 steve
* Detect constant lessthen-equal expressions.
*
* Revision 1.65 1999/09/16 04:18:15 steve
* elaborate concatenation repeats.
*
* Revision 1.64 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.63 1999/09/13 03:10:59 steve
* Clarify msb/lsb in context of netlist. Properly
* handle part selects in lval and rval of expressions,
* and document where the least significant bit goes
* in NetNet objects.
*
* Revision 1.62 1999/09/11 04:43:17 steve
* Support ternary and <= operators in vvm.
*
* Revision 1.61 1999/09/08 04:05:30 steve
* Allow assign to not match rvalue width.
*
* Revision 1.60 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.59 1999/09/01 20:46:19 steve
* Handle recursive functions and arbitrary function
* references to other functions, properly pass
* function parameters and save function results.
*
* Revision 1.58 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.57 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.56 1999/08/18 04:00:02 steve
* Fixup spelling and some error messages. <[email protected]>
*
* Revision 1.55 1999/08/06 04:05:28 steve
* Handle scope of parameters.
*
+8 -5
View File
@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ident "$Id: netlist.txt,v 1.3 1999/07/24 02:11:20 steve Exp $"
#ident "$Id: netlist.txt,v 1.4 1999/09/29 00:03:27 steve Exp $"
Note that the netlist.h header contains detailed descriptions of how
@@ -53,14 +53,14 @@ in the vector.
Node and net pins can be connected together via the connect
function. Connections are transitive (A==B and B==c means A==C) so
connections accumulate on a link as items are connected to it. The
descructors for nets and nodes automatically arrange for pins to be
destructors for nets and nodes automatically arrange for pins to be
disconnected when the item is deleted, so that the netlist can be
changed during processing.
BEHAVIORAL ITEMS: NetProcTop, NetProc and derived classes
Behavioral items are not in general linked to the netlist. Instead,
they represent elabrated behavioral statements. The type of the object
they represent elaborated behavioral statements. The type of the object
implies what the behavior of the statement does. For example, a
NetCondit object represents an ``if'' statement, and carries a
condition expression and up to two alternative sub-statements.
@@ -105,7 +105,7 @@ structurally as events are like devices that trigger behavioral
statements.
However, typical expressions the behavioral description are
represented as a tree of NetExpr nodes. The derived clas of the node
represented as a tree of NetExpr nodes. The derived class of the node
encodes what kind of operator the node represents.
EXPRESSION BIT WIDTH
@@ -160,7 +160,7 @@ the NetESignal object.
HIERARCHY IN NETLISTS
The obvious hierarchical structure of verilog is the module. The
The obvious hierarchical structure of Verilog is the module. The
Verilog program may contain any number of instantiations of modules in
order to form an hierarchical design. However, the elaboration of the
design into a netlist erases module boundaries. Modules are expanded
@@ -189,6 +189,9 @@ some task calls. C++ programmers recognize this as inlining a task.)
$Log: netlist.txt,v $
Revision 1.4 1999/09/29 00:03:27 steve
Spelling fixes from Larry.
Revision 1.3 1999/07/24 02:11:20 steve
Elaborate task input ports.
+42
View File
@@ -0,0 +1,42 @@
#ifndef __netmisc_H
#define __netmisc_H
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: netmisc.h,v 1.1 1999/09/29 00:42:51 steve Exp $"
#endif
# include "netlist.h"
/*
* This funciton transforms an expression by padding the high bits
* with V0 until the expression has the desired width. This may mean
* not transforming the expression at all, if it is already wide
* enough.
*/
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid);
/*
* $Log: netmisc.h,v $
* Revision 1.1 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
*/
#endif
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (c) 1999 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pad_to_width.cc,v 1.1 1999/09/29 00:42:51 steve Exp $"
#endif
# include "netlist.h"
# include "netmisc.h"
/*
* This funciton transforms an expression by padding the high bits
* with V0 until the expression has the desired width. This may mean
* not transforming the expression at all, if it is already wide
* enough.
*/
NetExpr*pad_to_width(NetExpr*expr, unsigned wid)
{
if (wid > expr->expr_width()) {
verinum pad(verinum::V0, wid - expr->expr_width());
NetEConst*co = new NetEConst(pad);
NetEConcat*cc = new NetEConcat(2);
cc->set(0, co);
cc->set(1, expr);
cc->set_width(wid);
expr = cc;
}
return expr;
}
/*
* $Log: pad_to_width.cc,v $
* Revision 1.1 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
*/
+220 -117
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: parse.y,v 1.58 1999/08/03 04:48:51 steve Exp $"
#ident "$Id: parse.y,v 1.73 1999/09/30 02:43:02 steve Exp $"
#endif
# include "parse_misc.h"
@@ -109,7 +109,7 @@ extern void lex_end_table();
%type <text> net_decl_assign
%type <strings> net_decl_assigns
%type <mport> port port_reference port_reference_list
%type <mport> port port_opt port_reference port_reference_list
%type <mports> list_of_ports list_of_ports_opt
%type <wires> task_item task_item_list task_item_list_opt
@@ -129,6 +129,7 @@ extern void lex_end_table();
%type <expr> delay_value
%type <exprs> delay delay_opt delay_value_list
%type <exprs> expression_list
%type <exprs> assign assign_list
%type <exprs> range range_opt
%type <nettype> net_type
@@ -137,17 +138,19 @@ extern void lex_end_table();
%type <task> task_body
%type <function> func_body
%type <exprs> range_or_type_opt
%type <event_expr> event_expression_list
%type <event_expr> event_expression
%type <event_statement> event_control
%type <statement> statement statement_opt
%type <statement_list> statement_list
%left '?' ':'
%right '?' ':'
%left K_LOR
%left K_LAND
%left '|'
%left '^'
%left '&'
%left '^' K_NXOR K_NOR
%left '&' K_NAND
%left K_EQ K_NE K_CEQ K_CNE
%left K_GE K_LE '<' '>'
%left K_LS K_RS
@@ -155,6 +158,10 @@ extern void lex_end_table();
%left '*' '/' '%'
%left UNARY_PREC
/* to resolve dangling else ambiguity: */
%nonassoc less_than_K_else
%nonassoc K_else
%%
source_file
@@ -162,9 +169,23 @@ source_file
| source_file description
;
/* The block_item_decl is used in function definitions, task
definitions, module definitions and named blocks. Wherever a new
scope is entered, the source may declare new registers and
integers. This rule matches those declarations. The containing
rule has presumably set up the scope. */
block_item_decl
: K_reg range_opt register_variable_list ';'
: K_reg range register_variable_list ';'
{ pform_set_net_range($3, $2);
delete $2;
delete $3;
}
| K_reg register_variable_list ';'
{ delete $2; }
| K_integer list_of_variables ';'
{ pform_set_reg_integer($2);
delete $2;
}
;
block_item_decls
@@ -196,7 +217,7 @@ case_item
$$ = tmp;
}
| error ':' statement_opt
{ yyerror(@1, "Incomprehensible case expression.");
{ yyerror(@1, "error: Incomprehensible case expression.");
yyerrok;
}
;
@@ -230,11 +251,12 @@ defparam_assign
: identifier '=' expression
{ PExpr*tmp = $3;
if (!pform_expression_is_constant(tmp)) {
yyerror(@3, "parameter value must be constant.");
yyerror(@3, "error: parameter value "
"must be constant.");
delete tmp;
tmp = 0;
}
yyerror(@1, "Sorry, defparam assignments not supported.");
yyerror(@1, "sorry: defparam assignments not supported.");
delete $1;
delete $3;
}
@@ -243,8 +265,8 @@ defparam_assign
defparam_assign_list
: defparam_assign
| range defparam_assign
{ yyerror(@1, "Ranges in parameter definition "
"are not supported.");
{ yywarn(@1, "Ranges in parameter definition "
"are not supported.");
delete $1;
}
| defparam_assign_list ',' defparam_assign
@@ -270,7 +292,7 @@ delay_value
: NUMBER
{ verinum*tmp = $1;
if (tmp == 0) {
yyerror(@1, "XXXX internal error: delay.");
yyerror(@1, "internal error: delay.");
$$ = 0;
} else {
$$ = new PENumber(tmp);
@@ -313,10 +335,10 @@ description
event_control
: '@' IDENTIFIER
{ yyerror(@1, "Sorry, event control not supported.");
{ yyerror(@1, "sorry: event control not supported.");
$$ = 0;
}
| '@' '(' event_expression ')'
| '@' '(' event_expression_list ')'
{ PEventStatement*tmp = new PEventStatement(*$3);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@@ -324,11 +346,22 @@ event_control
$$ = tmp;
}
| '@' '(' error ')'
{ yyerror(@1, "Malformed event control expression.");
{ yyerror(@1, "error: Malformed event control expression.");
$$ = 0;
}
;
event_expression_list
: event_expression
{ $$ = $1; }
| event_expression_list K_or event_expression
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
}
;
event_expression
: K_posedge expression
{ PEEvent*tmp = new PEEvent(NetNEvent::POSEDGE, $2);
@@ -354,12 +387,6 @@ event_expression
(*tl)[0] = tmp;
$$ = tl;
}
| event_expression K_or event_expression
{ svector<PEEvent*>*tmp = new svector<PEEvent*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
}
;
expression
@@ -469,6 +496,18 @@ expression
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_NOR expression
{ PEBinary*tmp = new PEBinary('O', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_NXOR expression
{ PEBinary*tmp = new PEBinary('X', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression '<' expression
{ PEBinary*tmp = new PEBinary('<', $1, $3);
tmp->set_file(@2.text);
@@ -579,7 +618,7 @@ expr_primary
$$ = tmp;
}
| REALTIME
{ yyerror(@1, "Sorry, real constants not supported.");
{ yyerror(@1, "sorry: real constants not supported.");
delete $1;
$$ = 0;
}
@@ -628,13 +667,15 @@ expr_primary
$$ = tmp;
}
| SYSTEM_IDENTIFIER '(' expression_list ')'
{ yyerror(@2, "Sorry, function calls not supported.");
$$ = 0;
{ PECallFunction*tmp = new PECallFunction($1, *$3);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| '(' expression ')'
{ $$ = $2; }
| '(' expression ':' expression ':' expression ')'
{ yyerror(@2, "Sorry, (min:typ:max) not supported.");
{ yyerror(@2, "sorry: (min:typ:max) not supported.");
$$ = $4;
delete $2;
delete $6;
@@ -649,7 +690,8 @@ expr_primary
| '{' expression '{' expression_list '}' '}'
{ PExpr*rep = $2;
if (!pform_expression_is_constant($2)) {
yyerror(@2, "Repeat expression must be constant.");
yyerror(@2, "error: Repeat expression "
"must be constant.");
delete rep;
delete $2;
rep = 0;
@@ -667,31 +709,45 @@ func_body
: function_item_list statement
{ $$ = new PFunction($1, $2); }
| function_item_list
{ yyerror(@1, "function body has no statement."); }
{ yyerror(@1, "error: function body has no statement.");
$$ = new PFunction($1, 0);
}
;
/* A function_item is either a block item (i.e. a reg or integer
declaration) or an input declaration. There are no output or
inout ports. */
function_item
: K_input range_opt list_of_variables ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT, $2, $3);
= pform_make_task_ports(NetNet::PINPUT, $2, $3,
@1.text, @1.first_line);
delete $2;
delete $3;
$$ = tmp;
}
| K_reg range_opt list_of_variables ';'
{ $$ = 0; }
| K_integer list_of_variables ';'
| block_item_decl
{ $$ = 0; }
;
/* A function_item_list only lists the input/output/inout
declarations. The integer and reg declarations are handled in
place, so are not listed. The list builder needs to account for
the possibility that the various parts may be NULL. */
function_item_list
: function_item
{ $$ = $1; }
| function_item_list function_item
{ svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
delete $1;
delete $2;
$$ = tmp;
{ if ($1 && $2) {
svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
delete $1;
delete $2;
$$ = tmp;
} else if ($1) {
$$ = $1;
} else {
$$ = $2;
}
}
;
@@ -798,19 +854,19 @@ identifier
: IDENTIFIER
{ $$ = $1; }
| HIDENTIFIER
{ yyerror(@1, "Sorry, qualified identifiers not supported.");
{ yyerror(@1, "sorry: qualified identifiers not supported.");
$$ = $1;
}
;
list_of_ports
: port
: port_opt
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(1);
(*tmp)[0] = $1;
$$ = tmp;
}
| list_of_ports ',' port
| list_of_ports ',' port_opt
{ svector<Module::port_t*>*tmp
= new svector<Module::port_t*>(*$1, $3);
delete $1;
@@ -820,7 +876,6 @@ list_of_ports
list_of_ports_opt
: '(' list_of_ports ')' { $$ = $2; }
| '(' ')' { $$ = 0; }
| { $$ = 0; }
;
@@ -854,7 +909,7 @@ lavalue
{ PEIdent*tmp = new PEIdent($1);
PExpr*sel = $3;
if (! pform_expression_is_constant(sel)) {
yyerror(@2, "Bit select in lvalue must "
yyerror(@2, "eror: Bit select in lvalue must "
"contain a constant expression.");
delete sel;
} else {
@@ -922,6 +977,26 @@ lpvalue
}
;
assign
: lavalue '=' expression
{ svector<PExpr*>*tmp = new svector<PExpr*>(2);
(*tmp)[0] = $1;
(*tmp)[1] = $3;
$$ = tmp;
}
;
assign_list
: assign_list ',' assign
{ svector<PExpr*>*tmp = new svector<PExpr*>(*$1, *$3);
delete $1;
delete $3;
$$ = tmp;
}
| assign
{ $$ = $1; }
;
module
: K_module IDENTIFIER list_of_ports_opt ';'
{ pform_startmodule($2, $3);
@@ -958,7 +1033,7 @@ module_item
delete $3;
}
| K_trireg charge_strength_opt range_opt delay_opt list_of_variables ';'
{ yyerror(@1, "Sorry, trireg nets not supported.");
{ yyerror(@1, "sorry: trireg nets not supported.");
delete $3;
}
| port_type range_opt list_of_variables ';'
@@ -969,20 +1044,10 @@ module_item
}
delete $3;
}
| K_reg range register_variable_list ';'
{ pform_set_net_range($3, $2);
delete $2;
delete $3;
}
| K_reg register_variable_list ';'
{ delete $2; }
| K_integer register_variable_list ';'
{ pform_set_reg_integer($2);
delete $2;
}
| block_item_decl
| K_defparam defparam_assign_list ';'
| K_event list_of_variables ';'
{ yyerror(@1, "Sorry, named events not supported.");
{ yyerror(@1, "sorry: named events not supported.");
delete $2;
}
| K_parameter parameter_assign_list ';'
@@ -990,18 +1055,11 @@ module_item
{ pform_makegates($1, $2, $3);
}
| IDENTIFIER delay_opt gate_instance_list ';'
{ pform_make_modgates($1, $3);
{ pform_make_modgates($1, $2, $3);
delete $1;
if ($2) {
yyerror(@2, "Sorry, parameter override not supported.");
delete $2;
}
}
| K_assign delay_opt lavalue '=' expression ';'
{ PGAssign*tmp = pform_make_pgassign($3, $5, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
}
| K_assign delay_opt assign_list ';'
{ pform_make_pgassign_list($3, $2, @1.text, @1.first_line); }
| K_assign error '=' expression ';'
| K_always statement
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $2);
@@ -1032,7 +1090,7 @@ module_item
{ PFunction *tmp = $6;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
pform_set_function($3, $6);
pform_set_function($3, $2, $6);
delete $3;
}
| K_specify specify_item_list K_endspecify
@@ -1045,7 +1103,7 @@ module_item
delete $7;
}
| KK_attribute '(' error ')' ';'
{ yyerror(@1, "Misformed $attribute parameter list."); }
{ yyerror(@1, "error: Misformed $attribute parameter list."); }
;
module_item_list
@@ -1105,7 +1163,8 @@ parameter_assign
: IDENTIFIER '=' expression
{ PExpr*tmp = $3;
if (!pform_expression_is_constant(tmp)) {
yyerror(@3, "parameter value must be constant.");
yyerror(@3, "error: parameter value "
"must be constant.");
delete tmp;
tmp = 0;
}
@@ -1117,7 +1176,7 @@ parameter_assign
parameter_assign_list
: parameter_assign
| range parameter_assign
{ yyerror(@1, "Ranges in parameter definition "
{ yywarn(@1, "Ranges in parameter definition "
"are not supported.");
delete $1;
}
@@ -1159,6 +1218,11 @@ port
}
;
port_opt
: port { $$ = $1; }
| { $$ = 0; }
;
port_reference
: IDENTIFIER
{ Module::port_t*ptmp = new Module::port_t(1);
@@ -1177,11 +1241,11 @@ port_reference
wtmp->set_file(@1.text);
wtmp->set_lineno(@1.first_line);
if (!pform_expression_is_constant($3)) {
yyerror(@3, "msb expression of port bit select "
yyerror(@3, "error: msb expression of port bit select "
"must be constant.");
}
if (!pform_expression_is_constant($5)) {
yyerror(@5, "lsb expression of port bit select "
yyerror(@5, "error: lsb expression of port bit select "
"must be constant.");
}
wtmp->set_range($3, $5);
@@ -1192,7 +1256,7 @@ port_reference
$$ = ptmp;
}
| IDENTIFIER '[' error ']'
{ yyerror(@1, "invalid port bit select");
{ yyerror(@1, "error: invalid port bit select");
Module::port_t*ptmp = new Module::port_t(1);
PWire*wtmp = new PWire($1, NetNet::IMPLICIT,
NetNet::PIMPLICIT);
@@ -1229,7 +1293,7 @@ port_name
$$ = tmp;
}
| PORTNAME '(' error ')'
{ yyerror(@3, "invalid port connection expression.");
{ yyerror(@3, "error: invalid port connection expression.");
portname_t*tmp = new portname_t;
tmp->name = $1;
tmp->parm = 0;
@@ -1269,12 +1333,12 @@ range
: '[' expression ':' expression ']'
{ svector<PExpr*>*tmp = new svector<PExpr*> (2);
if (!pform_expression_is_constant($2))
yyerror(@2, "msb of range must be constant.");
yyerror(@2, "error: msb of range must be constant.");
(*tmp)[0] = $2;
if (!pform_expression_is_constant($4))
yyerror(@4, "msb of range must be constant.");
yyerror(@4, "error: msb of range must be constant.");
(*tmp)[1] = $4;
@@ -1288,12 +1352,12 @@ range_opt
;
range_or_type_opt
: range { }
| K_integer
| K_real
| K_realtime
| K_time
|
: range { $$ = $1; }
| K_integer { $$ = 0; }
| K_real { $$ = 0; }
| K_realtime { $$ = 0; }
| K_time { $$ = 0; }
| { $$ = 0; }
;
/* The register_variable rule is matched only when I am parsing
variables in a "reg" definition. I therefore know that I am
@@ -1307,16 +1371,16 @@ register_variable
}
| IDENTIFIER '=' expression
{ pform_makewire(@1, $1, NetNet::REG);
yyerror(@2, "net declaration assignment to reg/integer not allowed.");
yyerror(@2, "error: net declaration assignment to reg/integer not allowed.");
delete $3;
$$ = $1;
}
| IDENTIFIER '[' expression ':' expression ']'
{ pform_makewire(@1, $1, NetNet::REG);
if (! pform_expression_is_constant($3))
yyerror(@3, "msb of register range must be constant.");
yyerror(@3, "error: msb of register range must be constant.");
if (! pform_expression_is_constant($5))
yyerror(@3, "lsb of register range must be constant.");
yyerror(@3, "error: lsb of register range must be constant.");
pform_set_reg_idx($1, $3, $5);
$$ = $1;
}
@@ -1340,8 +1404,7 @@ register_variable_list
specify_item
: K_specparam specparam_list ';'
| specify_simple_path '=' '(' expression_list ')' ';'
{ /* yyerror(@1, "Sorry, specify path declarations not supported."); */
delete $4;
{ delete $4;
}
;
@@ -1357,8 +1420,7 @@ specify_simple_path
specparam
: IDENTIFIER '=' expression
{ /* yyerror(@1, "Sorry, specparam assignments not supported."); */
delete $1;
{ delete $1;
delete $3;
}
;
@@ -1372,7 +1434,7 @@ spec_polarity: '+' | '-' | ;
statement
: K_assign lavalue '=' expression ';'
{ yyerror(@1, "Sorry, procedural continuous assign not supported.");
{ yyerror(@1, "sorry: procedural continuous assign not supported.");
$$ = 0;
}
| K_begin statement_list K_end
@@ -1409,16 +1471,16 @@ statement
| K_begin error K_end
{ yyerrok; }
| K_deassign lavalue';'
{ yyerror(@1, "Sorry, deassign not supported.");
{ yyerror(@1, "sorry:, deassign not supported.");
$$ = 0;
}
| K_disable IDENTIFIER ';'
{ yyerror(@1, "Sorry, disable statements not supported.");
{ yyerror(@1, "sorry: disable statements not supported.");
delete $2;
$$ = 0;
}
| K_force lavalue '=' expression ';'
{ yyerror(@1, "Sorry, procedural force assign not supported.");
{ yyerror(@1, "sorry: procedural force assign not supported.");
$$ = 0;
}
| K_forever statement
@@ -1434,14 +1496,16 @@ statement
delete $2;
$$ = tmp;
}
| K_release lavalue ';'
{ yyerror(@1, "Sorry, release not supported.");
$$ = 0;
}
| K_repeat '(' expression ')' statement
{ PRepeat*tmp = new PRepeat($3, $5);
| K_fork ':' IDENTIFIER
{ pform_push_scope($3); }
block_item_decls_opt
statement_list K_join
{ pform_pop_scope();
PBlock*tmp = new PBlock($3, PBlock::BL_PAR, *$6);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $3;
delete $6;
$$ = tmp;
}
| K_fork K_join
@@ -1450,24 +1514,38 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_fork ':' IDENTIFIER K_join
{ PBlock*tmp = new PBlock(PBlock::BL_PAR);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_release lavalue ';'
{ yyerror(@1, "sorry: release not supported.");
$$ = 0;
}
| K_repeat '(' expression ')' statement
{ PRepeat*tmp = new PRepeat($3, $5);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_case '(' expression ')' case_items K_endcase
{ PCase*tmp = new PCase($3, $5);
{ PCase*tmp = new PCase(NetCase::EQ, $3, $5);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_casex '(' expression ')' case_items K_endcase
{ PCase*tmp = new PCase($3, $5);
{ PCase*tmp = new PCase(NetCase::EQX, $3, $5);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
yywarn(@1, "casex not properly supported, using case.");
$$ = tmp;
}
| K_casez '(' expression ')' case_items K_endcase
{ PCase*tmp = new PCase($3, $5);
{ PCase*tmp = new PCase(NetCase::EQZ, $3, $5);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
yywarn(@1, "casez not properly supported, using case.");
$$ = tmp;
}
| K_case '(' expression ')' error K_endcase
@@ -1476,7 +1554,7 @@ statement
{ yyerrok; }
| K_casez '(' expression ')' error K_endcase
{ yyerrok; }
| K_if '(' expression ')' statement_opt
| K_if '(' expression ')' statement_opt %prec less_than_K_else
{ PCondit*tmp = new PCondit($3, $5, 0);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@@ -1488,12 +1566,12 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_if '(' error ')' statement_opt
{ yyerror(@1, "Malformed conditional expression.");
| K_if '(' error ')' statement_opt %prec less_than_K_else
{ yyerror(@1, "error: Malformed conditional expression.");
$$ = $5;
}
| K_if '(' error ')' statement_opt K_else statement_opt
{ yyerror(@1, "Malformed conditional expression.");
{ yyerror(@1, "error: Malformed conditional expression.");
$$ = $5;
}
| K_for '(' lpvalue '=' expression ';' expression ';'
@@ -1506,16 +1584,16 @@ statement
| K_for '(' lpvalue '=' expression ';' expression ';'
error ')' statement
{ $$ = 0;
yyerror(@9, "Error in for loop step assigment.");
yyerror(@9, "error: Error in for loop step assigment.");
}
| K_for '(' lpvalue '=' expression ';' error ';'
lpvalue '=' expression ')' statement
{ $$ = 0;
yyerror(@7, "Error in for loop condition expression.");
yyerror(@7, "error: Error in for loop condition expression.");
}
| K_for '(' error ')' statement
{ $$ = 0;
yyerror(@3, "Incomprehensible for loop.");
yyerror(@3, "error: Incomprehensible for loop.");
}
| K_while '(' expression ')' statement
{ PWhile*tmp = new PWhile($3, $5);
@@ -1523,12 +1601,12 @@ statement
}
| K_while '(' error ')' statement
{ $$ = 0;
yyerror(@3, "Error in while loop condition.");
yyerror(@3, "error: Error in while loop condition.");
}
| delay statement_opt
{ PExpr*del = (*$1)[0];
if ($1->count() != 1)
yyerror(@1, "Sorry, delay lists not supported here.");
yyerror(@1, "sorry: delay lists not supported here.");
PDelayStatement*tmp = new PDelayStatement(del, $2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
@@ -1537,7 +1615,7 @@ statement
| event_control statement_opt
{ PEventStatement*tmp = $1;
if (tmp == 0) {
yyerror(@1, "Invalid event control.");
yyerror(@1, "error: Invalid event control.");
$$ = 0;
} else {
tmp->set_statement($2);
@@ -1559,12 +1637,34 @@ statement
| lpvalue '=' delay expression ';'
{ PExpr*del = (*$3)[0];
if ($3->count() != 1)
yyerror(@1, "Sorry, delay lists not supported here.");
yyerror(@1, "sorry: Delay lists not supported here.");
PAssign*tmp = new PAssign($1,del,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue K_LE delay expression ';'
{ PExpr*del = (*$3)[0];
if ($3->count() != 1)
yyerror(@1, "sorry: Delay lists not supported here.");
PAssignNB*tmp = new PAssignNB($1,del,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue '=' event_control expression ';'
{ PAssign*tmp = new PAssign($1,$3,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| lpvalue K_LE event_control expression ';'
{ yyerror(@1, "sorry: Event controls not supported here.");
PAssignNB*tmp = new PAssignNB($1,$4);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_wait '(' expression ')' statement_opt
{ PEventStatement*tmp;
PEEvent*etmp = new PEEvent(NetNEvent::POSITIVE, $3);
@@ -1621,7 +1721,7 @@ statement
$$ = tmp;
}
| error ';'
{ yyerror(@1, "malformed statement");
{ yyerror(@1, "error: malformed statement");
yyerrok;
$$ = new PNoop;
}
@@ -1654,24 +1754,27 @@ task_body
task_item
: block_item_decl
{ $$ = 0; }
{ $$ = new svector<PWire*>(0); }
| K_input range_opt list_of_variables ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINPUT, $2, $3);
= pform_make_task_ports(NetNet::PINPUT, $2,
$3, @1.text, @1.first_line);
delete $2;
delete $3;
$$ = tmp;
}
| K_output range_opt list_of_variables ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::POUTPUT, $2, $3);
= pform_make_task_ports(NetNet::POUTPUT, $2, $3,
@1.text, @1.first_line);
delete $2;
delete $3;
$$ = tmp;
}
| K_inout range_opt list_of_variables ';'
{ svector<PWire*>*tmp
= pform_make_task_ports(NetNet::PINOUT, $2, $3);
= pform_make_task_ports(NetNet::PINOUT, $2, $3,
@1.text, @1.first_line);
delete $2;
delete $3;
$$ = tmp;
+5 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: parse_misc.cc,v 1.2 1998/11/07 17:05:05 steve Exp $"
#ident "$Id: parse_misc.cc,v 1.3 1999/09/29 21:15:31 steve Exp $"
#endif
# include "parse_misc.h"
@@ -48,7 +48,7 @@ void yywarn(const YYLTYPE&loc, const char*msg)
if (loc.text)
cerr << loc.text << ":";
cerr << loc.first_line << ": warning -- " << msg << endl;
cerr << loc.first_line << ": warning: " << msg << endl;
}
int VLwrap()
@@ -58,6 +58,9 @@ int VLwrap()
/*
* $Log: parse_misc.cc,v $
* Revision 1.3 1999/09/29 21:15:31 steve
* Standardize formatting of warning messages.
*
* Revision 1.2 1998/11/07 17:05:05 steve
* Handle procedural conditional, and some
* of the conditional expressions.
+103 -16
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform.cc,v 1.37 1999/08/03 04:14:49 steve Exp $"
#ident "$Id: pform.cc,v 1.46 1999/09/30 01:22:37 steve Exp $"
#endif
# include "compiler.h"
@@ -42,7 +42,9 @@ static Module*pform_cur_module = 0;
/*
* The scope stack and the following functions handle the processing
* of scope. As I enter a scope, the push function is called, and as I
* leave a scope the opo function is called.
* leave a scope the pop function is called.
*
* The top module is not included in the scope list.
*/
struct scope_name_t {
string name;
@@ -97,6 +99,15 @@ static unsigned long evaluate_delay(PExpr*delay)
void pform_startmodule(const string&name, svector<Module::port_t*>*ports)
{
assert( pform_cur_module == 0 );
/* The parser parses ``module foo()'' as having one
unconnected port, but it is really a module with no
ports. Fix it up here. */
if (ports && (ports->count() == 1) && ((*ports)[0] == 0)) {
delete ports;
ports = 0;
}
pform_cur_module = new Module(name, ports);
delete ports;
}
@@ -296,6 +307,7 @@ void pform_makegates(PGBuiltin::Type type,
*/
static void pform_make_modgate(const string&type,
const string&name,
svector<PExpr*>*overrides,
svector<PExpr*>*wires,
const string&fn, unsigned ln)
{
@@ -306,7 +318,7 @@ static void pform_make_modgate(const string&type,
return;
}
PGate*cur = new PGModule(type, name, wires);
PGate*cur = new PGModule(type, name, overrides, wires);
cur->set_file(fn);
cur->set_lineno(ln);
pform_cur_module->add_gate(cur);
@@ -314,6 +326,7 @@ static void pform_make_modgate(const string&type,
static void pform_make_modgate(const string&type,
const string&name,
svector<PExpr*>*overrides,
svector<portname_t*>*bind,
const string&fn, unsigned ln)
{
@@ -332,27 +345,29 @@ static void pform_make_modgate(const string&type,
pins[idx].parm = curp->parm;
}
PGate*cur = new PGModule(type, name, pins, npins);
PGate*cur = new PGModule(type, name, overrides, pins, npins);
cur->set_file(fn);
cur->set_lineno(ln);
pform_cur_module->add_gate(cur);
}
void pform_make_modgates(const string&type, svector<lgate>*gates)
void pform_make_modgates(const string&type,
svector<PExpr*>*overrides,
svector<lgate>*gates)
{
for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) {
lgate cur = (*gates)[idx];
if (cur.parms_by_name) {
pform_make_modgate(type, cur.name, cur.parms_by_name,
pform_make_modgate(type, cur.name, overrides, cur.parms_by_name,
cur.file, cur.lineno);
} else if (cur.parms) {
pform_make_modgate(type, cur.name, cur.parms, cur.file,
pform_make_modgate(type, cur.name, overrides, cur.parms, cur.file,
cur.lineno);
} else {
svector<PExpr*>*wires = new svector<PExpr*>(0);
pform_make_modgate(type, cur.name, wires, cur.file,
pform_make_modgate(type, cur.name, overrides, wires, cur.file,
cur.lineno);
}
}
@@ -378,6 +393,20 @@ PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
return cur;
}
void pform_make_pgassign_list(svector<PExpr*>*alist,
svector<PExpr*>*del,
const string& text,
unsigned lineno)
{
PGAssign*tmp;
for (unsigned idx = 0 ; idx < alist->count()/2 ; idx += 1) {
tmp = pform_make_pgassign((*alist)[2*idx],
(*alist)[2*idx+1], del);
tmp->set_file(text);
tmp->set_lineno(lineno);
}
}
void pform_makewire(const vlltype&li, const string&nm,
NetNet::Type type)
{
@@ -465,8 +494,11 @@ void pform_set_port_type(const string&name, NetNet::PortType pt)
*/
svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
const svector<PExpr*>*range,
const list<string>*names)
const list<string>*names,
const string& file,
unsigned lineno)
{
assert(names);
svector<PWire*>*res = new svector<PWire*>(0);
for (list<string>::const_iterator cur = names->begin()
; cur != names->end() ; cur ++ ) {
@@ -480,6 +512,8 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
curw->set_port_type(pt);
} else {
curw = new PWire(name, NetNet::IMPLICIT_REG, pt);
curw->set_file(file);
curw->set_lineno(lineno);
pform_cur_module->add_wire(curw);
}
@@ -500,8 +534,21 @@ void pform_set_task(const string&name, PTask*task)
pform_cur_module->add_task(name, task);
}
void pform_set_function(const string&name, PFunction *func)
/*
* This function is called to fill out the definition of the function
* with the trappings that are discovered after the basic function
* name is parsed.
*/
void pform_set_function(const string&name, svector<PExpr*>*ra, PFunction *func)
{
PWire*out = new PWire(name+"."+name, NetNet::REG, NetNet::POUTPUT);
if (ra) {
assert(ra->count() == 2);
out->set_range((*ra)[0], (*ra)[1]);
delete ra;
}
pform_cur_module->add_wire(out);
func->set_output(out);
pform_cur_module->add_function(name, func);
}
@@ -536,21 +583,26 @@ void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r)
{
PWire*cur = pform_cur_module->get_wire(name);
if (cur == 0) {
VLerror("name is not a valid net.");
VLerror(" error: name is not a valid net.");
return;
}
cur->set_memory_idx(l, r);
}
/*
* This function attaches a range to a given name. The function is
* only called by the parser within the scope of the net declaration,
* and the name that I receive only has the tail component.
*/
static void pform_set_net_range(const string&name, const svector<PExpr*>*range)
{
assert(range);
assert(range->count() == 2);
PWire*cur = pform_cur_module->get_wire(name);
PWire*cur = pform_cur_module->get_wire(scoped_name(name));
if (cur == 0) {
VLerror("name is not a valid net.");
VLerror(" error: name is not a valid net.");
return;
}
@@ -573,6 +625,7 @@ void pform_set_net_range(list<string>*names, const svector<PExpr*>*range)
void pform_set_parameter(const string&name, PExpr*expr)
{
pform_cur_module->parameters[name] = expr;
pform_cur_module->param_names.push_back(name);
}
void pform_set_port_type(list<string>*names, NetNet::PortType pt)
@@ -584,12 +637,18 @@ void pform_set_port_type(list<string>*names, NetNet::PortType pt)
}
}
static void pform_set_reg_integer(const string&name)
static void pform_set_reg_integer(const string&nm)
{
string name = scoped_name(nm);
PWire*cur = pform_cur_module->get_wire(name);
if (cur == 0) {
cur = new PWire(name, NetNet::INTEGER, NetNet::NOT_A_PORT);
pform_cur_module->add_wire(cur);
} else {
bool rc = cur->set_wire_type(NetNet::INTEGER);
assert(rc);
}
assert(cur);
bool rc = cur->set_wire_type(NetNet::INTEGER);
assert(rc);
cur->set_range(new PENumber(new verinum(INTEGER_WIDTH-1, INTEGER_WIDTH)),
new PENumber(new verinum(0UL, INTEGER_WIDTH)));
@@ -655,6 +714,34 @@ int pform_parse(const char*path, map<string,Module*>&modules,
/*
* $Log: pform.cc,v $
* Revision 1.46 1999/09/30 01:22:37 steve
* Handle declaration of integers (including scope) in functions.
*
* Revision 1.45 1999/09/21 00:58:33 steve
* Get scope right when setting the net range.
*
* Revision 1.44 1999/09/17 02:06:26 steve
* Handle unconnected module ports.
*
* Revision 1.43 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.42 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
* Revision 1.41 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.40 1999/08/27 15:08:37 steve
* continuous assignment lists.
*
* Revision 1.39 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.38 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.37 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
+25 -5
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform.h,v 1.27 1999/08/03 04:14:49 steve Exp $"
#ident "$Id: pform.h,v 1.31 1999/09/10 05:02:09 steve Exp $"
#endif
# include "netlist.h"
@@ -121,7 +121,7 @@ extern void pform_set_net_range(list<string>*names, const svector<PExpr*>*);
extern void pform_set_reg_idx(const string&name, PExpr*l, PExpr*r);
extern void pform_set_reg_integer(list<string>*names);
extern void pform_set_task(const string&, PTask*);
extern void pform_set_function(const string&, PFunction*);
extern void pform_set_function(const string&, svector<PExpr*>*, PFunction*);
extern void pform_set_attrib(const string&name, const string&key,
const string&value);
extern void pform_set_type_attrib(const string&name, const string&key,
@@ -141,18 +141,25 @@ extern void pform_makegates(PGBuiltin::Type type,
svector<PExpr*>*delay,
svector<lgate>*gates);
extern void pform_make_modgates(const string&type, svector<lgate>*gates);
extern void pform_make_modgates(const string&type,
svector<PExpr*>*overrides,
svector<lgate>*gates);
/* Make a continuous assignment node, with optional bit- or part- select. */
extern PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval,
svector<PExpr*>*delays);
extern void pform_make_pgassign_list(svector<PExpr*>*alist,
svector<PExpr*>*del,
const string& text,
unsigned lineno);
/* Given a port type and a list of names, make a list of wires that
can be used as task port information. */
extern svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
const svector<PExpr*>*range,
const list<string>*names);
const list<string>*names,
const string& file,
unsigned lineno);
/*
@@ -167,6 +174,19 @@ extern void pform_dump(ostream&out, Module*mod);
/*
* $Log: pform.h,v $
* Revision 1.31 1999/09/10 05:02:09 steve
* Handle integers at task parameters.
*
* Revision 1.30 1999/08/27 15:08:37 steve
* continuous assignment lists.
*
* Revision 1.29 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.28 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.27 1999/08/03 04:14:49 steve
* Parse into pform arbitrarily complex module
* port declarations.
+106 -22
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: pform_dump.cc,v 1.34 1999/08/03 04:49:13 steve Exp $"
#ident "$Id: pform_dump.cc,v 1.44 1999/09/30 02:43:02 steve Exp $"
#endif
/*
@@ -37,6 +37,12 @@ ostream& operator << (ostream&out, const PExpr&obj)
return out;
}
ostream& operator << (ostream&o, const PDelays&d)
{
d.dump_delays(o);
return o;
}
void PExpr::dump(ostream&out) const
{
out << typeid(*this).name();
@@ -65,7 +71,7 @@ void PECallFunction::dump(ostream &out) const
{
out << name_ << "(";
parms_[0]->dump(out);
for (unsigned idx = 0; idx < parms_.count(); ++idx) {
for (unsigned idx = 1; idx < parms_.count(); ++idx) {
out << ", ";
parms_[idx]->dump(out);
}
@@ -209,7 +215,7 @@ void PGate::dump_pins(ostream&out) const
}
}
void PGate::dump_delays(ostream&out) const
void PDelays::dump_delays(ostream&out) const
{
if (delay_[0] && delay_[1] && delay_[2])
out << "#(" << *delay_[0] << "," << *delay_[1] << "," <<
@@ -221,10 +227,15 @@ void PGate::dump_delays(ostream&out) const
}
void PGate::dump_delays(ostream&out) const
{
delay_.dump_delays(out);
}
void PGate::dump(ostream&out) const
{
out << " " << typeid(*this).name() << " ";
dump_delays(out);
delay_.dump_delays(out);
out << " " << get_name() << "(";
dump_pins(out);
out << ");" << endl;
@@ -268,12 +279,25 @@ void PGBuiltin::dump(ostream&out) const
void PGModule::dump(ostream&out) const
{
out << " " << type_ << " " << get_name() << "(";
out << " " << type_ << " ";
if (overrides_) {
out << "#(";
out << *((*overrides_)[0]);
for (unsigned idx = 1 ; idx < overrides_->count() ; idx += 1) {
out << "," << *((*overrides_)[idx]);
}
out << ") ";
}
out << get_name() << "(";
if (pins_) {
out << "." << pins_[0].name << "(" << *pins_[0].parm << ")";
out << "." << pins_[0].name << "(";
if (pins_[0].parm) out << *pins_[0].parm;
out << ")";
for (unsigned idx = 1 ; idx < npins_ ; idx += 1) {
out << ", ." << pins_[idx].name << "(" <<
*pins_[idx].parm << ")";
out << ", ." << pins_[idx].name << "(";
if (pins_[idx].parm)
out << *pins_[idx].parm;
out << ")";
}
} else {
dump_pins(out);
@@ -294,18 +318,14 @@ void Statement::dump(ostream&out, unsigned ind) const
void PAssign::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "";
out << *lval() << " = ";
if (delay()) out << "#" << *delay() << " ";
out << *rval() << ";";
out << *lval() << " = " << delay_ << " " << *rval() << ";";
out << " /* " << get_line() << " */" << endl;
}
void PAssignNB::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "";
out << *lval() << " <= ";
if (delay()) out << "#" << *delay() << " ";
out << *rval() << ";";
out << *lval() << " <= " << delay_ << " " << *rval() << ";";
out << " /* " << get_line() << " */" << endl;
}
@@ -317,7 +337,10 @@ void PBlock::dump(ostream&out, unsigned ind) const
out << endl;
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) {
list_[idx]->dump(out, ind+2);
if (list_[idx])
list_[idx]->dump(out, ind+2);
else
out << setw(ind+2) << "" << "/* NOOP */ ;" << endl;
}
out << setw(ind) << "" << "end" << endl;
@@ -345,8 +368,19 @@ void PCallTask::dump(ostream&out, unsigned ind) const
void PCase::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "case (" << *expr_ << ") /* " <<
get_line() << " */" << endl;
out << setw(ind) << "";
switch (type_) {
case NetCase::EQ:
out << "case";
break;
case NetCase::EQX:
out << "casex";
break;
case NetCase::EQZ:
out << "casez";
break;
}
out << " (" << *expr_ << ") /* " << get_line() << " */" << endl;
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
PCase::Item*cur = (*items_)[idx];
@@ -377,7 +411,10 @@ void PCase::dump(ostream&out, unsigned ind) const
void PCondit::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "if (" << *expr_ << ")" << endl;
if_->dump(out, ind+3);
if (if_)
if_->dump(out, ind+3);
else
out << setw(ind) << ";" << endl;
if (else_) {
out << setw(ind) << "" << "else" << endl;
else_->dump(out, ind+3);
@@ -430,13 +467,17 @@ void PForStatement::dump(ostream&out, unsigned ind) const
void PFunction::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "output " << out_->name() << ";" << endl;
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
out << setw(ind) << "";
out << "input ";
out << (*ports_)[idx]->name() << ";" << endl;
}
statement_->dump(out, ind);
if (statement_)
statement_->dump(out, ind);
else
out << setw(ind) << "" << "/* NOOP */" << endl;
}
void PRepeat::dump(ostream&out, unsigned ind) const
@@ -464,7 +505,10 @@ void PTask::dump(ostream&out, unsigned ind) const
out << (*ports_)[idx]->name() << ";" << endl;
}
statement_->dump(out, ind);
if (statement_)
statement_->dump(out, ind);
else
out << setw(ind) << "" << "/* NOOP */" << endl;
}
@@ -496,6 +540,12 @@ void Module::dump(ostream&out) const
for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) {
port_t*cur = ports_[idx];
if (cur == 0) {
out << " unconnected" << endl;
continue;
}
switch (cur->wires[0]->get_port_type()) {
case NetNet::PINPUT:
out << " input ." << cur->name << "(";
@@ -522,8 +572,11 @@ void Module::dump(ostream&out) const
typedef map<string,PExpr*>::const_iterator parm_iter_t;
for (parm_iter_t cur = parameters.begin()
; cur != parameters.end() ; cur ++) {
out << " parameter " << (*cur).first << " = " <<
*(*cur).second << ";" << endl;
out << " parameter " << (*cur).first << " = ";
if ((*cur).second)
out << *(*cur).second << ";" << endl;
else
out << "/* ERROR */;" << endl;
}
// Iterate through and display all the wires.
@@ -619,6 +672,37 @@ void PUdp::dump(ostream&out) const
/*
* $Log: pform_dump.cc,v $
* Revision 1.44 1999/09/30 02:43:02 steve
* Elaborate ~^ and ~| operators.
*
* Revision 1.43 1999/09/30 00:48:50 steve
* Cope with errors during ternary operator elaboration.
*
* Revision 1.42 1999/09/29 21:15:58 steve
* Handle some mor missing names.
*
* Revision 1.41 1999/09/29 20:23:53 steve
* Handle empty named ports in the dump.
*
* Revision 1.40 1999/09/29 18:36:04 steve
* Full case support
*
* Revision 1.39 1999/09/17 02:06:26 steve
* Handle unconnected module ports.
*
* Revision 1.38 1999/09/08 02:24:39 steve
* Empty conditionals (pmonta@imedia.com)
*
* Revision 1.37 1999/09/04 19:11:46 steve
* Add support for delayed non-blocking assignments.
*
* Revision 1.36 1999/08/25 22:22:41 steve
* elaborate some aspects of functions.
*
* Revision 1.35 1999/08/23 16:48:39 steve
* Parameter overrides support from Peter Monta
* AND and XOR support wide expressions.
*
* Revision 1.34 1999/08/03 04:49:13 steve
* Proper port type names.
*
+280
View File
@@ -0,0 +1,280 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: set_width.cc,v 1.6 1999/10/05 06:19:46 steve Exp $"
#endif
/*
* This file contains set_width methods for the various NetExpr
* classes. The set_width method is used by elaboration to ask the
* expression to resize itself. If the expression can't, then the
* set_width method will return false and the caller will arrange for
* whatever is needed to deal with the size mismatch.
*/
# include "netlist.h"
# include "netmisc.h"
# include <typeinfo>
bool NetExpr::set_width(unsigned w)
{
cerr << typeid(*this).name() << ": set_width(unsigned) "
"not implemented." << endl;
expr_width(w);
return false;
}
bool NetEBinary::set_width(unsigned w)
{
bool flag = true;
switch (op_) {
case 'l': // left shift (<<)
case 'r': // right shift (>>)
flag = left_->set_width(w);
expr_width(w);
break;
/* The default rule is that the operands of the binary
operator might as well use the same width as the
output from the binary operation. */
default:
expr_width(left_->expr_width() > right_->expr_width()
? left_->expr_width() : right_->expr_width());
cerr << "NetEBinary::set_width(): Using default for " <<
op_ << "." << endl;
flag = false;
case '%':
case '/':
flag = left_->set_width(w) && flag;
flag = right_->set_width(w) && flag;
expr_width(w);
break;
}
return flag;
}
/*
* The bitwise logical operators have operands the same size as the
* result. Anything else is a mess.
*/
bool NetEBAdd::set_width(unsigned w)
{
unsigned wid = w;
if (left_->expr_width() > wid)
wid = left_->expr_width();
if (right_->expr_width() > wid)
wid = right_->expr_width();
left_->set_width(wid);
right_->set_width(wid);
if (left_->expr_width() < wid) {
NetExpr*tmp = pad_to_width(left_, wid);
assert(tmp);
left_ = tmp;
}
if (right_->expr_width() < wid) {
NetExpr*tmp = pad_to_width(right_, wid);
assert(tmp);
right_ = tmp;
}
expr_width(wid);
return wid == w;
}
/*
* The bitwise logical operators have operands the same size as the
* result. Anything else is a mess.
*/
bool NetEBBits::set_width(unsigned w)
{
bool flag = true;
flag = left_->set_width(w) && flag;
flag = right_->set_width(w) && flag;
if (flag)
expr_width(w);
return flag;
}
/*
* Comparison operators allow the subexpressions to have
* their own natural width, but the comparison operator result has a
* fixed width of 1.
*/
bool NetEBComp::set_width(unsigned w)
{
bool flag = true;
return (w == 1);
}
bool NetEBLogic::set_width(unsigned w)
{
bool flag;
flag = left_->set_width(right_->expr_width());
if (!flag)
flag = right_->set_width(left_->expr_width());
return (w == 1);
}
/*
* The shift operator allows the shift amount to have its own
* natural width. The width of the operator result is the width of the
* left operand, the value that is to be shifted.
*/
bool NetEBShift::set_width(unsigned w)
{
bool flag;
flag = left_->set_width(w);
return flag;
}
/*
* Add up the widths from all the expressions that are concatenated
* together. This is the width of the expression, tough luck if you
* want it otherwise.
*
* If during the course of elaboration one of the sub-expressions is
* broken, then don't count it in the width. This doesn't really
* matter because the null expression is indication of an error and
* the compiler will not go beyond elaboration.
*/
bool NetEConcat::set_width(unsigned w)
{
unsigned sum = 0;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1)
if (parms_[idx] != 0)
sum += parms_[idx]->expr_width();
sum *= repeat_;
expr_width(sum);
if (sum != w) return false;
return true;
}
bool NetEConst::set_width(unsigned w)
{
if (w > value_.len())
return false;
assert(w <= value_.len());
value_ = verinum(value_, w);
expr_width(w);
return true;
}
bool NetEMemory::set_width(unsigned w)
{
if (w != mem_->width())
return false;
expr_width(w);
return true;
}
bool NetEParam::set_width(unsigned)
{
return false;
}
/*
* The signal should automatically pad with zeros to get to th desired
* width. Do not allow signal bits to be truncated, however.
*/
bool NetESignal::set_width(unsigned w)
{
if (w != pin_count())
return false;
return true;
}
bool NetESubSignal::set_width(unsigned w)
{
if (w != 1) return false;
return true;
}
bool NetETernary::set_width(unsigned w)
{
bool flag = true;
flag = flag && true_val_->set_width(w);
flag = flag && false_val_->set_width(w);
expr_width(true_val_->expr_width());
return flag;
}
/*
* XXXX FIX ME: For now, just take whatever the caller says as my
* width. What I really need to do is note the width of the output
* parameter of the function definition and take that into account.
*/
bool NetEUFunc::set_width(unsigned wid)
{
expr_width(wid);
return true;
}
bool NetEUnary::set_width(unsigned w)
{
bool flag = true;
switch (op_) {
case '~':
case '-':
flag = expr_->set_width(w);
break;
default:
flag = expr_width() == w;
break;
}
expr_width(w);
return flag;
}
/*
* $Log: set_width.cc,v $
* Revision 1.6 1999/10/05 06:19:46 steve
* Add support for reduction NOR.
*
* Revision 1.5 1999/10/05 04:02:10 steve
* Relaxed width handling for <= assignment.
*
* Revision 1.4 1999/09/29 00:42:51 steve
* Allow expanding of additive operators.
*
* Revision 1.3 1999/09/23 03:56:57 steve
* Support shift operators.
*
* Revision 1.2 1999/09/23 02:27:50 steve
* comparison parameter width is self determined.
*
* Revision 1.1 1999/09/23 00:21:55 steve
* Move set_width methods into a single file,
* Add the NetEBLogic class for logic expressions,
* Fix error setting with of && in if statements.
*
*/
+19 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: t-null.cc,v 1.4 1999/07/03 02:12:52 steve Exp $"
#ident "$Id: t-null.cc,v 1.8 1999/10/05 03:26:37 steve Exp $"
#endif
# include "netlist.h"
@@ -33,19 +33,36 @@ static class target_null_t : public target_t {
void bufz(ostream&os, const NetBUFZ*) { }
void memory(ostream&, const NetMemory*) { }
void task_def(ostream&, const NetTaskDef*) { }
void net_assign(ostream&os, const NetAssign*) { }
void net_assign_nb(ostream&os, const NetAssignNB*) { }
void net_esignal(ostream&, const NetESignal*) { }
void net_event(ostream&, const NetNEvent*) { }
void proc_block(ostream&, const NetBlock*) { }
bool proc_block(ostream&, const NetBlock*) { return true; }
void proc_condit(ostream&, const NetCondit*) { }
void proc_delay(ostream&, const NetPDelay*) { }
void proc_event(ostream&, const NetPEvent*) { }
void proc_forever(ostream&, const NetForever*) { }
void proc_repeat(ostream&, const NetRepeat*) { }
void proc_stask(ostream&, const NetSTask*) { }
void proc_utask(ostream&os, const NetUTask*) { }
} target_null_obj;
extern const struct target tgt_null = { "null", &target_null_obj };
/*
* $Log: t-null.cc,v $
* Revision 1.8 1999/10/05 03:26:37 steve
* null target ignore assignment nodes.
*
* Revision 1.7 1999/09/30 21:27:29 steve
* Ignore user task definitions.
*
* Revision 1.6 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.5 1999/09/17 02:06:26 steve
* Handle unconnected module ports.
*
* Revision 1.4 1999/07/03 02:12:52 steve
* Elaborate user defined tasks.
*
+7 -3
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: t-verilog.cc,v 1.7 1999/08/01 16:34:50 steve Exp $"
#ident "$Id: t-verilog.cc,v 1.8 1999/09/22 16:57:24 steve Exp $"
#endif
/*
@@ -43,7 +43,7 @@ class target_verilog : public target_t {
virtual void logic(ostream&os, const NetLogic*);
virtual void bufz(ostream&os, const NetBUFZ*);
virtual void start_process(ostream&os, const NetProcTop*);
virtual void proc_block(ostream&os, const NetBlock*);
virtual bool proc_block(ostream&os, const NetBlock*);
virtual void proc_delay(ostream&os, const NetPDelay*);
virtual void proc_event(ostream&os, const NetPEvent*);
virtual void proc_stask(ostream&os, const NetSTask*);
@@ -173,13 +173,14 @@ void target_verilog::emit_expr_(ostream&os, const NetExpr*expr)
}
}
void target_verilog::proc_block(ostream&os, const NetBlock*net)
bool target_verilog::proc_block(ostream&os, const NetBlock*net)
{
os << setw(indent_) << "" << "begin" << endl;
indent_ += 4;
net->emit_recurse(os, this);
indent_ -= 4;
os << setw(indent_) << "" << "end" << endl;
return true;
}
void target_verilog::proc_delay(ostream&os, const NetPDelay*net)
@@ -271,6 +272,9 @@ const struct target tgt_verilog = {
/*
* $Log: t-verilog.cc,v $
* Revision 1.8 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.7 1999/08/01 16:34:50 steve
* Parse and elaborate rise/fall/decay times
* for gates, and handle the rules for partial
+742 -320
View File
File diff suppressed because it is too large Load Diff
+24 -2
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: t-xnf.cc,v 1.7 1999/07/17 03:39:11 steve Exp $"
#ident "$Id: t-xnf.cc,v 1.9 1999/08/25 22:22:08 steve Exp $"
#endif
/* XNF BACKEND
@@ -71,6 +71,7 @@ class target_xnf : public target_t {
void end_design(ostream&os, const Design*);
void signal(ostream&os, const NetNet*);
void logic(ostream&os, const NetLogic*);
void bufz(ostream&os, const NetBUFZ*);
void udp(ostream&os, const NetUDP*);
private:
@@ -82,7 +83,7 @@ class target_xnf : public target_t {
};
/*
* This function takes a signal name and mangles it into an equivilent
* This function takes a signal name and mangles it into an equivalent
* name that is suitable to the XNF format.
*/
string target_xnf::mangle(const string&name)
@@ -313,6 +314,21 @@ void target_xnf::logic(ostream&os, const NetLogic*net)
os << "END" << endl;
}
void target_xnf::bufz(ostream&os, const NetBUFZ*net)
{
static int warned_once=0;
if (!warned_once) {
cerr << "Warning: BUFZ object found for xnf output."
" Try -Fnobufz." << endl;
warned_once=1;
}
os << "SYM, " << mangle(net->name()) << ", BUF, LIBVER=2.0.0" << endl;
assert(net->pin_count() == 2);
draw_pin(os, "O", net->pin(0));
draw_pin(os, "I", net->pin(1));
os << "END" << endl;
}
void target_xnf::udp(ostream&os, const NetUDP*net)
{
string lca = net->attribute("XNF-LCA");
@@ -333,6 +349,12 @@ extern const struct target tgt_xnf = { "xnf", &target_xnf_obj };
/*
* $Log: t-xnf.cc,v $
* Revision 1.9 1999/08/25 22:22:08 steve
* handle bufz in XNF backend.
*
* Revision 1.8 1999/08/18 04:00:02 steve
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
*
* Revision 1.7 1999/07/17 03:39:11 steve
* simplified process scan for targets.
*
+50 -7
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: target.cc,v 1.15 1999/07/17 19:51:00 steve Exp $"
#ident "$Id: target.cc,v 1.20 1999/09/22 16:57:24 steve Exp $"
#endif
# include "target.h"
@@ -41,6 +41,12 @@ void target_t::memory(ostream&os, const NetMemory*)
"Unhandled memory." << endl;
}
void target_t::func_def(ostream&os, const NetFuncDef*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled function definition." << endl;
}
void target_t::task_def(ostream&os, const NetTaskDef*)
{
cerr << "target (" << typeid(*this).name() << "): "
@@ -63,6 +69,12 @@ void target_t::udp(ostream&os, const NetUDP*)
"Unhandled UDP." << endl;
}
void target_t::lpm_add_sub(ostream&, const NetAddSub*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetAddSub." << endl;
}
void target_t::net_assign(ostream&os, const NetAssign*)
{
}
@@ -79,21 +91,23 @@ void target_t::net_const(ostream&os, const NetConst*)
"Unhandled CONSTANT node." << endl;
}
void target_t::net_esignal(ostream&os, const NetESignal*)
void target_t::net_esignal(ostream&os, const NetESignal*net)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled Expression Signal node." << endl;
net->dump_node(cerr, 4);
}
void target_t::net_event(ostream&os, const NetNEvent*)
void target_t::net_event(ostream&os, const NetNEvent*net)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled EVENT net node." << endl;
net->dump_node(cerr, 4);
}
void target_t::process(ostream&os, const NetProcTop*top)
bool target_t::process(ostream&os, const NetProcTop*top)
{
top->statement()->emit_proc(os, this);
return top->statement()->emit_proc(os, this);
}
void target_t::proc_assign(ostream&os, const NetAssign*)
@@ -114,10 +128,17 @@ void target_t::proc_assign_nb(ostream&os, const NetAssignNB*)
"Unhandled non-blocking assignment." << endl;
}
void target_t::proc_block(ostream&os, const NetBlock*)
void target_t::proc_assign_mem_nb(ostream&os, const NetAssignMemNB*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled non-blocking memory assignment." << endl;
}
bool target_t::proc_block(ostream&os, const NetBlock*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled proc_block." << endl;
return false;
}
void target_t::proc_case(ostream&os, const NetCase*cur)
@@ -140,10 +161,11 @@ void target_t::proc_delay(ostream&os, const NetPDelay*)
"Unhandled proc_delay." << endl;
}
void target_t::proc_event(ostream&os, const NetPEvent*)
void target_t::proc_event(ostream&os, const NetPEvent*net)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled proc_event." << endl;
net->dump(cerr, 4);
}
void target_t::proc_forever(ostream&os, const NetForever*)
@@ -227,6 +249,12 @@ void expr_scan_t::expr_ternary(const NetETernary*)
"unhandled expr_ternary." << endl;
}
void expr_scan_t::expr_ufunc(const NetEUFunc*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
"unhandled function call." << endl;
}
void expr_scan_t::expr_unary(const NetEUnary*)
{
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
@@ -241,6 +269,21 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
/*
* $Log: target.cc,v $
* Revision 1.20 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.19 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.18 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.17 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.16 1999/08/18 04:00:02 steve
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
*
* Revision 1.15 1999/07/17 19:51:00 steve
* netlist support for ternary operator.
*
+22 -4
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: target.h,v 1.15 1999/07/17 19:51:00 steve Exp $"
#ident "$Id: target.h,v 1.19 1999/09/22 16:57:24 steve Exp $"
#endif
# include "netlist.h"
@@ -63,6 +63,10 @@ struct target_t {
/* Output a defined task. */
virtual void task_def(ostream&, const NetTaskDef*);
virtual void func_def(ostream&, const NetFuncDef*);
/* LPM style components are handled here. */
virtual void lpm_add_sub(ostream&os, const NetAddSub*);
/* Output a gate (called for each gate) */
virtual void logic(ostream&os, const NetLogic*);
@@ -76,13 +80,14 @@ struct target_t {
/* Output a process (called for each process). It is up to the
target to recurse if desired. */
virtual void process(ostream&os, const NetProcTop*);
virtual bool process(ostream&os, const NetProcTop*);
/* Various kinds of process nodes are dispatched through these. */
virtual void proc_assign(ostream&os, const NetAssign*);
virtual void proc_assign_mem(ostream&os, const NetAssignMem*);
virtual void proc_assign_nb(ostream&os, const NetAssignNB*);
virtual void proc_block(ostream&os, const NetBlock*);
virtual void proc_assign_mem_nb(ostream&os, const NetAssignMemNB*);
virtual bool proc_block(ostream&os, const NetBlock*);
virtual void proc_case(ostream&os, const NetCase*);
virtual void proc_condit(ostream&os, const NetCondit*);
virtual void proc_forever(ostream&os, const NetForever*);
@@ -109,6 +114,7 @@ struct expr_scan_t {
virtual void expr_signal(const NetESignal*);
virtual void expr_subsignal(const NetESubSignal*);
virtual void expr_ternary(const NetETernary*);
virtual void expr_ufunc(const NetEUFunc*);
virtual void expr_unary(const NetEUnary*);
virtual void expr_binary(const NetEBinary*);
};
@@ -117,7 +123,7 @@ struct expr_scan_t {
/* The emit functions take a design and emit it to the output stream
using the specified target. If the target is given by name, it is
located in the target_table and used. */
extern void emit(ostream&o, const Design*des, const char*type);
extern bool emit(ostream&o, const Design*des, const char*type);
/* This function takes a fully qualified verilog name (which may have,
for example, dots in it) and produces a mangled version that can be
@@ -130,6 +136,18 @@ extern const struct target *target_table[];
/*
* $Log: target.h,v $
* Revision 1.19 1999/09/22 16:57:24 steve
* Catch parallel blocks in vvm emit.
*
* Revision 1.18 1999/09/15 01:55:06 steve
* Elaborate non-blocking assignment to memories.
*
* Revision 1.17 1999/09/03 04:28:38 steve
* elaborate the binary plus operator.
*
* Revision 1.16 1999/08/31 22:38:29 steve
* Elaborate and emit to vvm procedural functions.
*
* Revision 1.15 1999/07/17 19:51:00 steve
* netlist support for ternary operator.
*
+86
View File
@@ -0,0 +1,86 @@
.TH verilog 1 "Septemeber 13th, 1999" Version 19990913
.SH NAME
verilog - Icarus Verilog Driver
.SH SYNOPSIS
.B verilog
[-Dmacro[=defn]] [-Iincludepath] [-X] [-o outputfilename] [-s topmodule] sourcefile[s]
.SH DESCRIPTION
.PP
\fIverilog\fP is the compiler driver script for compiling Verilog code
to either a VVM-format (Verilog Virtual Machine) for simulation or to
XNF (Xilinx Netlist Format) to be used in Xilinx FPGA's.
\fIverilog\fP is just massaging the input switches and then calls
the preprocessor (ivlpp), the compiler (ivl) and (optional) the C++
compiler.
Please read the official documentation (very minimal at this point)
on how to use \fIivl et al\fP, since this man page just describes the
"easy startscript" \fIverilog\fP.
.SH OPTIONS
.l
\fIverilog\fP accepts the following options:
.TP 8
.B -D\fImacro\fP
Defines macro \fImacro\fP with the string `1' as its definition.
.TP 8
.B -D\fImacro=defn\fP
Defines macro \fImacro\fP as \fIdefn\fP.
.TP 8
.B -I\fIincludepath\fP
Append path \fIincludepath\fP to list of paths searched for include files.
.TP 8
.B -X
Generate XNF files as output. Default is VVM-format.
.TP 8
.B -x
Executes the generated file directly after compilation.
.TP 8
.B -o \fIfilename\fP
Place output in the file \fIfilename\fP. If not given, \fIverilog\fP tries to
make a guess; if the input filename is "hello.v", the output
filename will be "hello" (for VVM target) or "hello.xnf" (for XNF target).
If several files are given on the command line, the \fIlast\fP filename will
be used.
.TP 8
.B -s \fItopmodule name\fP
To explicitly set the module \fIivl\fP will use as a top-level module.
.SH EXAMPLES
These examples assume that you have a Verilog source file called hello.v in
the current directory
To compile hello.v to an executable file called hello:
verilog hello.v
To compile hello.v to an executable file called runnable:
verilog -o runnable hello.v
To compile hello.v to a file in XNF-format called hello.xnf
verilog -X hello.v
.SH "ENVIRONMENT"
.ta \w'VPI_MODULE_PATH 'u
VPI_MODULE_PATH path to PLI modules
.SH "AUTHORS"
.nf
.ta \w'verilog 'u
verilog Stefan Petersen ([email protected])
ivlpp Steve Williams ([email protected])
ivl Steve Williams ([email protected])
.SH SEE ALSO
.BR ivlpp (N/A)
.BR ivl (N/A)
.SH COPYRIGHT
.nf
Copyright \(co 1999 Stefan Petersen
This document can be freely redistributed according to the terms of the
GNU General Public License version 2.0
+117
View File
@@ -0,0 +1,117 @@
#!/bin/sh
# verilog - A wrapper shell script for ivl
# Copyright (C) 1999 Stefan Petersen ([email protected])
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# Setup variables
execPath=@bindir@
execIVLPP=${execPath}/ivlpp
execIVL=${execPath}/ivl
execCpp=/usr/bin/g++
vvmTarget="-t vvm"
xnfTarget="-t xnf"
tmpDir=/tmp
tmpPPFile=${tmpDir}/ivl$$.pp
tmpCCFile=${tmpDir}/ivl$$.cc
VPIModulePath=@libdir@/ivl:.
target=${vvmTarget}
targetSuffix=""
# If VPI module path aren't set up, warn at least
if test -z "${VPI_MODULE_PATH}" ; then
echo "Missing environment variable VPI_MODULE_PATH.";
echo "To be able to execute, set VPI_MODULE_PATH to ${VPIModulePath}";
fi
# Try to extract given parameters
parameter=`getopt D:I:Xxo:s: "$@"`
eval set -- "${parameter}"
while true ; do
case "$1" in
-D) extDefines="${extDefines} -D$2" ; shift 2 ;;
-I) extIncPath="${extIncPath} -I $2" ; shift 2 ;;
-X) targetSuffix=".xnf" ; target=${xnfTarget} ; shift ;;
-o) outputFile=$2 ; shift 2 ;;
-s) topModule="-s $2 " ; shift 2 ;;
-x) execute="true"; shift ;;
--) shift ; break ;;
*) echo "Internal error! Arg is $1 " ; exit 1 ;;
esac
done
# The rest is filenames
verilogFile=$@;
if test -z "${verilogFile}" ; then
echo "Missing infile";
echo "verilog [-Dmacro[=defn]] [-Iincludepath] [-X] [-x] [-o outputfilename] [-s topmodule] sourcefile[s]" ;
exit 1;
fi
# If no output file is given should we guess one or...?
# Assumes a few silly things if several files are given
if test -z "${outputFile}" ; then
outputFile=`echo ${verilogFile} | sed -e 's;.* ;;' | sed -e 's;\..*$;;'`
outputFile="${outputFile}${targetSuffix}" ;
fi
# Preprocess
${execIVLPP} ${extDefines} ${extIncPath} -L -o ${tmpPPFile} ${verilogFile}
if test $? -ne 0 ; then
echo "Preprocessing failed. Terminating compilation."
rm -f ${tmpPPFile}
exit 1
fi
# Compile preprocessed verilog file
${execIVL} ${target} -o ${tmpCCFile} ${topModule} ${tmpPPFile}
if test $? -ne 0 ; then
echo "Verilog compilation failed. Terminating compilation."
rm -f ${tmpCCFile}
exit 1
fi
rm -f ${tmpPPFile}
case "${targetSuffix}" in
.xnf) mv ${tmpCCFile} ${outputFile} ;;
"") ${execCpp} -rdynamic ${tmpCCFile} -o ${outputFile} -lvvm -ldl ;
if test $? -ne 0 ; then
echo "C++ compilation failed. Terminating compilation."
rm -f ${tmpCCFile}
exit 1
fi
rm -f ${tmpCCFile} ;;
*) echo "Internal error in target compilation." ; exit 1
esac
if test ${execute} ; then
./${outputFile}
fi
+56
View File
@@ -0,0 +1,56 @@
HOW IT WORKS
The VPI interface for Icarus Verilog works by creating from a
collection of PLI applications a single vpi module. The vpi module
includes compiled code for the applications linked together (with any
other libraries that the applications need) into a module with a
single exported symbol, the vlog_startup_routines array.
The product that wishes to invoke the module (normally at run time)
loads the module, locates the vlog_startup_routines table, and calls
all the startup routines contained in that table. It is possible for a
product to link with many modules. In that case, all the modules are
linked in and startup routines are called in order.
The product that uses vpi modules uses the environment variable
VPI_MODULE_PATH as a ':' separated list of directories. This is the
module search path. When a module is specified by name (using whatever
means the product supports) the module search path is scanned until
the module is located.
The special module name "system.vpi" is part of the core Icarus
Verilog distribution and includes implementations of the standard
system tasks/functions.
COMPILING A VPI MODULE (LINUX)
To compile a module, first compile down to object files all the PLI
applications that you wish to include in the module. Then, create a
small "C" source file that defines only the startup table like so:
extern void hello_register();
void (*vlog_startup_routines[])() = {
hello_register,
0
};
Compile this table source down to its object file, as well. Finally,
link the application with the command:
cc -o foo.vpi -shared <all the .o files>
No VPI libraries need to be included because the product that loads
the module will supply all the standard vpi functions. If you use any
non-vpi library functions, you may need to include libraries to
support them.
The resulting foo.vpi file is the vpi module. Place it in a location
where the product to use it can locate it.
CAVEAT EMPTOR
Only the calltf function is supported. The compiletf and sizetf
functions are invoked at compile time, and the ivl compiler does not
yet support VPI.
+3
View File
@@ -0,0 +1,3 @@
Makefile
system.vpi
dep
+81
View File
@@ -0,0 +1,81 @@
#
# This source code is free software; you can redistribute it
# and/or modify it in source code form under the terms of the GNU
# Library General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option)
# any later version. In order to redistribute the software in
# binary form, you will need a Picture Elements Binary Software
# License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc.,
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.4 1999/08/31 23:00:08 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.0
prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
VPATH = $(srcdir)
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
includedir = $(prefix)/include
CC = @CC@
CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CPPFLAGS = @CPPFLAGS@ @DEFS@
CXXFLAGS = @CXXFLAGS@
LDFLAGS = @LDFLAGS@
all: system.vpi
%.o dep/%.d: %.c
@[ -d dep ] || mkdir dep
$(CC) -Wall $(CPPFLAGS) -MD -c $< -o $*.o
mv $*.d dep
O = sys_table.o sys_display.o sys_finish.o
system.vpi: $O
$(CC) -shared -o $@ $O
clean:
rm -f *.o dep/*.d
install: all installdirs $(libdir)/ivl/system.vpi \
$(includedir)/vpi_user.h
$(libdir)/ivl/system.vpi: ./system.vpi
$(INSTALL_PROGRAM) ./system.vpi $(libdir)/ivl/system.vpi
$(includedir)/vpi_user.h: $(srcdir)/vpi_user.h
$(INSTALL_DATA) $(srcdir)/vpi_user.h $(includedir)/vpi_user.h
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(includedir) $(bindir) $(libdir)/ivl
uninstall:
rm -f $(libdir)/ivl/system.vpi
rm -f $(includedir)/vpi_user.h
-include $(patsubst %.o, dep/%.d, $O)
+239
View File
@@ -0,0 +1,239 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sys_display.c,v 1.2 1999/09/29 01:41:18 steve Exp $"
#endif
# include "vpi_user.h"
# include <assert.h>
# include <string.h>
# include <ctype.h>
# include <stdlib.h>
static void format_binary(vpiHandle argv, int fsize)
{
s_vpi_value value;
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
value.format = vpiBinStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
}
static void format_decimal(vpiHandle argv, int fsize)
{
s_vpi_value value;
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
value.format = vpiDecStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
}
static void format_hex(vpiHandle argv, int fsize)
{
s_vpi_value value;
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
value.format = vpiHexStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
}
static void format_m(vpiHandle argv, int fsize)
{
vpiHandle item = vpi_scan(argv);
if (item == 0) return;
vpi_printf("%s", vpi_get_str(vpiFullName, item));
}
/*
* If $display discovers a string as a parameter, this function is
* called to process it as a format string. I need the argv handle as
* well so that I can look for arguments as I move forward through the
* string.
*/
static void format(s_vpi_value*fmt, vpiHandle argv)
{
char buf[256];
char*cp = fmt->value.str;
assert(fmt->value.str);
while (*cp) {
size_t cnt = strcspn(cp, "%\\");
if (cnt > 0) {
if (cnt >= sizeof buf)
cnt = sizeof buf - 1;
strncpy(buf, cp, cnt);
buf[cnt] = 0;
vpi_printf("%s", buf);
cp += cnt;
} else if (*cp == '%') {
int fsize = -1;
cp += 1;
if (isdigit(*cp))
fsize = strtoul(cp, &cp, 10);
switch (*cp) {
case 0:
break;
case 'b':
case 'B':
format_binary(argv, fsize);
cp += 1;
break;
case 'd':
case 'D':
format_decimal(argv, fsize);
cp += 1;
break;
case 'h':
case 'H':
case 'x':
case 'X':
format_hex(argv, fsize);
cp += 1;
break;
case 'm':
format_m(argv, fsize);
cp += 1;
break;
case '%':
vpi_printf("%%");
cp += 1;
break;
default:
vpi_printf("%c", *cp);
cp += 1;
break;
}
} else {
cp += 1;
switch (*cp) {
case 0:
break;
case 'n':
vpi_printf("\n");
cp += 1;
break;
default:
vpi_printf("%c", *cp);
cp += 1;
}
}
}
}
static int sys_display_calltf(char *name)
{
s_vpi_value value;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item;
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
switch (vpi_get(vpiType, item)) {
case 0:
vpi_printf(" ");
break;
case vpiConstant:
value.format = vpiObjTypeVal;
vpi_get_value(item, &value);
switch (value.format) {
case vpiStringVal:
format(&value, argv);
break;
case vpiSuppressVal:
break;
default:
vpi_printf("?");
break;
}
break;
case vpiNet:
case vpiReg:
value.format = vpiBinStrVal;
vpi_get_value(item, &value);
vpi_printf("%s", value.value.str);
break;
case vpiTimeVar:
value.format = vpiTimeVal;
vpi_get_value(item, &value);
vpi_printf("%u", value.value.time->low);
break;
default:
vpi_printf("?");
break;
}
}
if (strcmp(name,"$display") == 0)
vpi_printf("\n");
return 0;
}
void sys_display_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = "$display";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$display";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$write";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$write";
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_display.c,v $
* Revision 1.2 1999/09/29 01:41:18 steve
* Support the $write system task, and have the
* vpi_scan function free iterators as needed.
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sys_finish.c,v 1.3 1999/08/28 02:10:44 steve Exp $"
#endif
# include "vpi_user.h"
static int sys_finish_calltf(char *xx)
{
vpi_sim_control(vpiFinish, 0);
return 0;
}
void sys_finish_register()
{
s_vpi_systf_data tf_data;
tf_data.type = vpiSysTask;
tf_data.tfname = "$finish";
tf_data.calltf = sys_finish_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
vpi_register_systf(&tf_data);
}
/*
* $Log: sys_finish.c,v $
* Revision 1.3 1999/08/28 02:10:44 steve
* Call the right vpiFinish code.
*
* Revision 1.2 1999/08/19 02:51:03 steve
* Add vpi_sim_control
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: sys_table.c,v 1.1 1999/08/15 01:23:56 steve Exp $"
#endif
extern void sys_finish_register();
extern void sys_display_register();
void (*vlog_startup_routines[])() = {
sys_finish_register,
sys_display_register,
0
};
/*
* $Log: sys_table.c,v $
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
+174
View File
@@ -0,0 +1,174 @@
#ifndef __vpi_user_H
#define __vpi_user_H
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_user.h,v 1.3 1999/08/19 02:51:03 steve Exp $"
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct __vpiHandle *vpiHandle;
/*
* This structure is created by the VPI application to provide hooks
* into the application that the compiler/simulator can access.
*/
typedef struct t_vpi_systf_data {
int type;
int subtype;
char *tfname;
int (*calltf)(char*);
int (*compiletf)(char*);
int (*sizetf)();
char *user_data;
} s_vpi_systf_data, *p_vpi_systf_data;
/* The type in the above structure can have one of the following
values: */
#define vpiSysTask 1
#define vpiSysFunc 2
typedef struct t_vpi_time {
int type;
unsigned int high;
unsigned int low;
double real;
} s_vpi_time, *p_vpi_time;
#define vpiScaledRealTime 1
#define vpiSimTime 2
#define vpiSuppressTime 3
/*
* This structure holds values that are passed back and forth between
* the simulator and the application.
*/
typedef struct t_vpi_value {
int format;
union {
char*str;
int scalar;
int integer;
double real;
struct t_vpi_time *time;
struct t_vpi_vecval *vector;
struct t_vpi_strengthval *strength;
char*misc;
} value;
} s_vpi_value, *p_vpi_value;
/* These are valid codes for the format of the t_vpi_value structure. */
#define vpiBinStrVal 1
#define vpiOctStrVal 2
#define vpiDecStrVal 3
#define vpiHexStrVal 4
#define vpiScalerVal 5
#define vpiIntVal 6
#define vpiReadVal 7
#define vpiStringVal 8
#define vpiVectorVal 9
#define vpiStrengthVal 10
#define vpiTimeVal 11
#define vpiObjTypeVal 12
#define vpiSuppressVal 13
/* OBJECT CODES */
#define vpiConstant 7
#define vpiNet 36
#define vpiReg 48
#define vpiSysTaskCall 57
#define vpiTimeVar 63
#define vpiSysTfCall 85
#define vpiArgument 89
/* PROPERTIES */
#define vpiType 1
#define vpiName 2
#define vpiFullName 3
#define vpiConstType 43
# define vpiDecConst 1
# define vpiRealConst 2
# define vpiBinaryConst 3
# define vpiOctConst 4
# define vpiHexConst 5
# define vpiStringConst 6
/* VPI FUNCTIONS */
extern void vpi_register_systf(const struct t_vpi_systf_data*ss);
extern void vpi_printf(const char*fmt, ...);
/*
* This function allows a vpi application to control the simulation
* engine. The operation parameter specifies the function to
* perform. The remaining parameters (if any) are interpreted by the
* operation. The vpi_sim_control definition was added to P1364-2000
* 14 July 1999. See PLI Task Force ID: PTF-161
*
* vpiFinish - perform the $finish operation, as soon as the user
* function returns. This operation takes a single
* parameter, a diagnostic exit code.
*
* vpiStop -
* vpiReset -
* vpiSetInteractiveScope -
*/
extern void vpi_sim_control(int operation, ...);
#define vpiStop 1
#define vpiFinish 2
#define vpiReset 3
#define vpiSetInteractiveScope 4
extern vpiHandle vpi_handle(int type, vpiHandle ref);
extern vpiHandle vpi_iterate(int type, vpiHandle ref);
extern vpiHandle vpi_scan(vpiHandle iter);
extern int vpi_get(int property, vpiHandle ref);
extern char* vpi_get_str(int property, vpiHandle ref);
extern void vpi_get_value(vpiHandle expr, p_vpi_value value);
extern int vpi_free_object(vpiHandle ref);
/* This is the table of startup routines included in each module. */
extern void (*vlog_startup_routines[])();
#ifdef __cplusplus
}
#endif
/*
* $Log: vpi_user.h,v $
* Revision 1.3 1999/08/19 02:51:03 steve
* Add vpi_sim_control
*
* Revision 1.2 1999/08/18 03:44:49 steve
* declare vou_sim_control
*
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
#endif
+18 -1
View File
@@ -16,6 +16,17 @@ So a sample command line to compile a Verilog file to C++ would be:
ivl -F nobufz -F sigfold -F propinit -t vvm -o foo.cc foo.vl
Once the program is compiled down to C++ code, it needs to be further
compiled and linked into an executable image. The command for doing
this is highly dependent on the system where you use Icarus
Verilog. For Linux, the compile command is typically:
c++ -rdynamic -o foo foo.cc -lvvm -ldl
On any system, the compiled program requires that the VPI_MODULE_PATH
be set to a ':' separated list of directories to search for vpi files,
the system.vpi file in particular. This is a run time requirement.
ATTRIBUTES
(none)
@@ -99,8 +110,14 @@ bits are at:
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
$Id: vvm.txt,v 1.1 1999/04/29 16:29:04 steve Exp $
$Id: vvm.txt,v 1.3 1999/08/18 03:45:36 steve Exp $
$Log: vvm.txt,v $
Revision 1.3 1999/08/18 03:45:36 steve
Update compile command line.
Revision 1.2 1999/08/15 01:23:56 steve
Convert vvm to implement system tasks with vpi.
Revision 1.1 1999/04/29 16:29:04 steve
Add vvm target documentation
+10 -6
View File
@@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.3 1999/05/09 01:24:59 steve Exp $"
#ident "$Id: Makefile.in,v 1.5 1999/08/28 02:10:57 steve Exp $"
#
#
SHELL = /bin/sh
@@ -36,7 +36,7 @@ libdir = $(exec_prefix)/lib
includedir = $(prefix)/include
CC = @CC@
CXX = @CXX@
CXX = @CXX@ -I../vpi
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
@@ -52,9 +52,8 @@ all: libvvm.a
$(CXX) -Wall -fno-exceptions $(CXXFLAGS) -MD -c $< -o $*.o
mv $*.d dep
TF = display.o
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_monitor.o vvm_pevent.o \
vvm_simulation.o vvm_thread.o $(TF)
vvm_simulation.o vvm_thread.o
libvvm.a: $O
rm -f $@
@@ -65,10 +64,11 @@ clean:
install: all installdirs $(libdir)/libvvm.a \
$(includedir)/vvm.h \
$(includedir)/vvm_calltf.h \
$(includedir)/vpi_priv.h \
$(includedir)/vvm_func.h \
$(includedir)/vvm_gates.h \
$(includedir)/vvm_thread.h
$(includedir)/vvm_thread.h \
$(includedir)/vvm_calltf.h
$(libdir)/libvvm.a: ./libvvm.a
$(INSTALL_PROGRAM) ./libvvm.a $(libdir)/libvvm.a
@@ -88,6 +88,9 @@ $(includedir)/vvm_gates.h: $(srcdir)/vvm_gates.h
$(includedir)/vvm_thread.h: $(srcdir)/vvm_thread.h
$(INSTALL_DATA) $(srcdir)/vvm_thread.h $(includedir)/vvm_thread.h
$(includedir)/vpi_priv.h: $(srcdir)/vpi_priv.h
$(INSTALL_DATA) $(srcdir)/vpi_priv.h $(includedir)/vpi_priv.h
installdirs: mkinstalldirs
$(srcdir)/mkinstalldirs $(includedir) $(bindir)
@@ -98,6 +101,7 @@ uninstall:
rm -f $(includedir)/vvm_func.h
rm -f $(includedir)/vvm_gates.h
rm -f $(includedir)/vvm_thread.h
rm -f $(includedir)/vpi_priv.h
-include $(patsubst %.o, dep/%.d, $O)
-264
View File
@@ -1,264 +0,0 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: display.cc,v 1.5 1999/05/31 15:46:36 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_calltf.h"
# include <iostream>
static void format_hex(vvm_simulation*sim, ostream&os,
class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::TIME:
os << sim->get_sim_time();
break;
case vvm_calltf_parm::NONE:
os << "z";
break;
case vvm_calltf_parm::ULONG:
os << ((parm->as_ulong()&1) ? "0" : "1");
break;
case vvm_calltf_parm::STRING:
os << parm->as_string();
break;
case vvm_calltf_parm::BITS:
unsigned c = 0;
for (unsigned idx = parm->as_bits()->get_width()
; idx > 0 ; idx -= 1)
c = (c << 1) | parm->as_bits()->get_bit(idx-1);
cout.form("%x",c);
break;
}
}
static void format_bit(vvm_simulation*sim, ostream&os,
class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::TIME:
os << (sim->get_sim_time()&1);
break;
case vvm_calltf_parm::NONE:
os << "z";
break;
case vvm_calltf_parm::ULONG:
os << ((parm->as_ulong()&1) ? "0" : "1");
break;
case vvm_calltf_parm::STRING:
os << parm->as_string();
break;
case vvm_calltf_parm::BITS:
for (unsigned idx = parm->as_bits()->get_width()
; idx > 0 ; idx -= 1)
os << parm->as_bits()->get_bit(idx-1);
break;
}
}
static void format_dec(vvm_simulation*sim, ostream&os,
class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::TIME:
os << sim->get_sim_time();
break;
case vvm_calltf_parm::NONE:
os << "0";
break;
case vvm_calltf_parm::ULONG:
os << parm->as_ulong();
break;
case vvm_calltf_parm::STRING:
os << parm->as_string();
break;
case vvm_calltf_parm::BITS: {
unsigned long val = 0;
unsigned long mask = 1;
const vvm_bits_t*bstr = parm->as_bits();
for (unsigned idx = 0 ; idx < bstr->get_width() ; idx += 1) {
if (bstr->get_bit(idx) == V1) val |= mask;
mask <<= 1;
}
os << val;
break;
}
}
}
static void format_name(ostream&os, class vvm_calltf_parm*parm)
{
switch (parm->type()) {
case vvm_calltf_parm::TIME:
os << "$time";
break;
case vvm_calltf_parm::NONE:
break;
case vvm_calltf_parm::ULONG:
os << parm->as_ulong();
break;
case vvm_calltf_parm::STRING:
os << "\"" << parm->as_string() << "\"";
break;
case vvm_calltf_parm::BITS:
os << parm->sig_name();
break;
}
}
static unsigned format(vvm_simulation*sim, const string&str,
unsigned nparms,
class vvm_calltf_parm*parms)
{
char prev = 0;
unsigned next_parm = 0;
unsigned idx = 0;
while (idx < str.length()) {
if (prev == '%') {
switch (str[idx]) {
case 'b':
case 'B':
format_bit(sim, cout, parms+next_parm);
next_parm += 1;
break;
case 'x':
case 'X':
case 'h':
case 'H':
format_hex(sim, cout, parms+next_parm);
next_parm += 1;
break;
case 'd':
case 'D':
format_dec(sim, cout, parms+next_parm);
next_parm += 1;
break;
case 'm':
case 'M':
format_name(cout, parms+next_parm);
next_parm += 1;
break;
case '%':
cout << str[idx];
break;
}
prev = 0;
} else {
if (str[idx] != '%')
cout << str[idx];
else
prev = '%';
}
idx += 1;
}
return next_parm;
}
void Sdisplay(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms)
{
for (unsigned idx = 0 ; idx < nparms ; idx += 1)
switch (parms[idx].type()) {
case vvm_calltf_parm::NONE:
cout << " ";
break;
case vvm_calltf_parm::TIME:
cout << sim->get_sim_time();
break;
case vvm_calltf_parm::ULONG:
cout << parms[idx].as_ulong();
break;
case vvm_calltf_parm::STRING:
idx += format(sim, parms[idx].as_string(),
nparms-idx-1, parms+idx+1);
break;
case vvm_calltf_parm::BITS:
cout << *parms[idx].as_bits();
break;
}
cout << endl;
}
class monitor_event : public vvm_event {
public:
monitor_event(vvm_simulation*sim,
unsigned nparms, class vvm_calltf_parm*parms)
{ sim_ = sim;
nparms_ = nparms;
parms_ = new vvm_calltf_parm[nparms];
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1)
parms_[idx] = parms[idx];
}
~monitor_event() { delete[]parms_; }
private:
vvm_simulation*sim_;
unsigned nparms_;
vvm_calltf_parm*parms_;
void event_function();
};
void monitor_event::event_function()
{
Sdisplay(sim_, "$display", nparms_, parms_);
}
static monitor_event*mon = 0;
void Smonitor(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms)
{
if (mon) delete mon;
mon = new monitor_event(sim, nparms, parms);
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
if (parms[idx].type() != vvm_calltf_parm::BITS)
continue;
parms[idx].as_mon()->enable(mon);
}
}
/*
* $Log: display.cc,v $
* Revision 1.5 1999/05/31 15:46:36 steve
* Handle time in more places.
*
* Revision 1.4 1999/05/12 04:02:17 steve
* Add %x support contributed by Steve Wilson.
*
* Revision 1.3 1999/01/01 01:44:40 steve
* Proberly print vectors in binary.
*
* Revision 1.2 1998/11/10 00:48:31 steve
* Add support it vvm target for level-sensitive
* triggers (i.e. the Verilog wait).
* Fix display of $time is format strings.
*
* Revision 1.1 1998/11/09 23:44:10 steve
* Add vvm library.
*
*/
+97
View File
@@ -0,0 +1,97 @@
#ifndef __vpi_priv_H
#define __vpi_priv_H
/*
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vpi_priv.h,v 1.1 1999/08/15 01:23:56 steve Exp $"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* This is the most basic type in the vpi implementation. A handle can
* exist to refer to most any of the supported vpi objects. The
* interpretation of the parts depends in general on the type of the
* object.
*/
struct __vpiHandle {
int type;
int subtype;
/* These are property values. */
char*full_name;
/* This pointer is used for to-one references. */
struct __vpiHandle*referent;
/* This pointer table is used for to-many refrences to
arguments, and is used by the vpiArgument iterator. */
struct __vpiHandle**arguments;
unsigned narguments;
/* These methods support the various vpi_get() functions. */
int (*get_)(int property, vpiHandle ref);
char* (*get_str_)(int property, vpiHandle ref);
/* This method is used to get a value. */
void (*get_value_)(struct __vpiHandle*expr, s_vpi_value*vp);
/* This is a value union, that reflect state or the value of a
handle. */
union {
unsigned unum;
struct vvm_bits_t*bits;
struct t_vpi_time time;
} val;
};
/* TYPE MEANINGS:
*
* vpiArgument
* This type of handle contains a single referent, the item that has
* many arguments. It is an iterator.
*
* vpiConstant
* Constant values, such as strings and numbers, are this type.
*
* vpiSysTaskCall
* This handle type represents a call to a system task. It has a
* to-many reference to argument expressions, and a to-one reference
* to a vpiUserSystf object.
*
* vpiTimeVar
* This type is a special kind of variable, that holds a time. The
* time value is a more complex structure then a single number. The
* type really seems to exist to implement the $time system variable.
*/
#ifdef __cplusplus
}
#endif
/*
* $Log: vpi_priv.h,v $
* Revision 1.1 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
*/
#endif
+51 -12
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm.h,v 1.9 1999/06/21 01:02:34 steve Exp $"
#ident "$Id: vvm.h,v 1.14 1999/10/06 01:28:18 steve Exp $"
#endif
# include <vector>
@@ -80,6 +80,15 @@ inline vvm_bit_t less_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
return c;
}
inline vvm_bit_t greater_with_cascade(vvm_bit_t l, vvm_bit_t r, vvm_bit_t c)
{
if (l == Vx) return Vx;
if (r == Vx) return Vx;
if (l > r) return V1;
if (l < r) return V0;
return c;
}
extern vvm_bit_t add_with_carry(vvm_bit_t l, vvm_bit_t r, vvm_bit_t&carry);
inline vvm_bit_t not(vvm_bit_t l)
@@ -117,6 +126,18 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits_[idx] = Vz;
}
vvm_bitset_t(const vvm_bitset_t<WIDTH>&that)
{ bits_ = that.bits_; }
vvm_bitset_t(const vvm_bits_t&that)
{ unsigned wid = WIDTH;
if (that.get_width() < WIDTH)
wid = that.get_width();
for (unsigned idx = 0 ; idx < wid ; idx += 1)
bits_[idx] = that.get_bit(idx);
for (unsigned idx = wid ; idx < WIDTH ; idx += 1)
bits_[idx] = V0;
}
vvm_bit_t operator[] (unsigned idx) const { return bits_[idx]; }
vvm_bit_t&operator[] (unsigned idx) { return bits_[idx]; }
@@ -124,13 +145,6 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
unsigned get_width() const { return WIDTH; }
vvm_bit_t get_bit(unsigned idx) const { return bits_[idx]; }
bool eequal(const vvm_bitset_t<WIDTH>&that) const
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
if (bits_[idx] != that.bits_[idx])
return false;
return true;
}
unsigned as_unsigned() const
{ unsigned result = 0;
for (unsigned idx = WIDTH ; idx > 0 ; idx -= 1) {
@@ -140,6 +154,12 @@ template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
return result;
}
vvm_bitset_t<WIDTH>& operator= (const vvm_bitset_t<WIDTH>&that)
{ if (this == &that) return *this;
bits_ = that.bits_;
return *this;
}
private:
vvm_bit_t bits_[WIDTH];
};
@@ -207,7 +227,11 @@ class vvm_simulation {
unsigned long get_sim_time() const { return time_; }
// The s_finish() method marks the simulation as finished and
// prevents more events being executed. The finished() method
// returns true if the s_finish() method has been called.
void s_finish();
bool finished() const;
private:
bool going_;
@@ -235,17 +259,17 @@ class vvm_simulation {
*/
class vvm_monitor_t {
public:
vvm_monitor_t(const string&);
vvm_monitor_t(const char*);
void trigger(vvm_simulation*sim)
{ if (event_) sim->monitor_event(event_); }
const string& name() const { return name_; }
const char* name() const { return name_; }
void enable(vvm_event*e) { event_ = e; }
private:
string name_;
const char* name_;
vvm_event*event_;
private: // not implemented
@@ -257,7 +281,7 @@ class vvm_monitor_t {
template <unsigned WIDTH> class vvm_signal_t : public vvm_monitor_t {
public:
vvm_signal_t(const string&n, vvm_bitset_t<WIDTH>*b)
vvm_signal_t(const char*n, vvm_bitset_t<WIDTH>*b)
: vvm_monitor_t(n), bits_(b)
{ }
@@ -280,6 +304,21 @@ template <unsigned WIDTH> class vvm_signal_t : public vvm_monitor_t {
/*
* $Log: vvm.h,v $
* Revision 1.14 1999/10/06 01:28:18 steve
* The $finish task should work immediately.
*
* Revision 1.13 1999/10/05 04:02:10 steve
* Relaxed width handling for <= assignment.
*
* Revision 1.12 1999/09/29 18:36:04 steve
* Full case support
*
* Revision 1.11 1999/09/28 01:13:15 steve
* Support in vvm > and >= behavioral operators.
*
* Revision 1.10 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
* Revision 1.9 1999/06/21 01:02:34 steve
* Add init to vvm_signal_t.
*
+480 -128
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -17,153 +17,505 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_calltf.cc,v 1.2 1999/05/31 15:46:36 steve Exp $"
#ident "$Id: vvm_calltf.cc,v 1.6 1999/09/29 01:41:18 steve Exp $"
#endif
# include "vvm_calltf.h"
# include <vpi_user.h>
# include "vpi_priv.h"
# include <new>
# include <iostream>
# include <assert.h>
# include <stdlib.h>
# include <stdarg.h>
# include <malloc.h>
# include <stdio.h>
# include <dlfcn.h>
vvm_calltf_parm::vvm_calltf_parm()
: type_(NONE)
{
}
# define MAX_PATHLEN 1024
vvm_calltf_parm::vvm_calltf_parm(TYPE t)
: type_(t)
{
assert((t == NONE) || (t == TIME));
}
/* This simulation pointer is used by vpi functions to get back to the
simulation. */
static vvm_simulation*vpi_sim;
void vvm_calltf_parm::release_()
{
switch (type_) {
case NONE:
case TIME:
case ULONG:
break;
case STRING:
((string*)string_)->string::~string();
break;
case BITS:
break;
}
type_ = NONE;
}
static vpiHandle vvm_vpi_cur_task;
vvm_calltf_parm& vvm_calltf_parm::operator= (unsigned long val)
{
release_();
type_ = ULONG;
ulong_ = val;
return *this;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (const string&val)
{
release_();
type_ = STRING;
new (string_) string (val);
return *this;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm::SIG&val)
{
release_();
type_ = BITS;
bits_ = val;
return *this;
}
vvm_calltf_parm& vvm_calltf_parm::operator= (const vvm_calltf_parm&that)
{
if (this == &that)
return *this;
release_();
switch (that.type_) {
case NONE:
case TIME:
type_ = that.type_;
break;
case ULONG:
type_ = ULONG;
ulong_ = that.ulong_;
break;
case STRING:
type_ = STRING;
new (string_) string (that.as_string());
break;
case BITS:
type_ = BITS;
bits_ = that.bits_;
break;
}
return *this;
}
vvm_calltf_parm::~vvm_calltf_parm()
{
release_();
}
extern void Sdisplay(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms);
extern void Smonitor(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms);
static void Sfinish(vvm_simulation*sim, const string&,
unsigned, class vvm_calltf_parm*)
{
sim->s_finish();
}
static struct {
const string name;
void (*func)(vvm_simulation*, const string&,
unsigned, class vvm_calltf_parm*);
} sys_table[] = {
{ "$display", &Sdisplay },
{ "$finish", &Sfinish },
{ "$monitor", &Smonitor },
{ "", 0 }
/*
* Keep a list of vpi_systf_data structures. This list is searched
* forward whenever a function is invoked by name, and items are
* pushed in front of the list whenever they are registered. This
* allows entries to override older entries.
*/
struct systf_entry {
struct systf_entry* next;
s_vpi_systf_data systf_data;
};
void vvm_calltask(vvm_simulation*sim, const string&fname,
unsigned nparms, class vvm_calltf_parm*parms)
static struct systf_entry*systf_list = 0;
extern "C" void vpi_register_systf(const struct t_vpi_systf_data*systf)
{
struct systf_entry*cur = new struct systf_entry;
cur->systf_data = *systf;
cur->systf_data.tfname = strdup(systf->tfname);
cur->next = systf_list;
systf_list = cur;
}
for (unsigned idx = 0 ; sys_table[idx].func ; idx += 1)
if (fname == sys_table[idx].name) {
sys_table[idx].func(sim, fname, nparms, parms);
return;
}
extern "C" void vpi_printf(const char*fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
cout << "Call " << fname << "(";
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
if (idx > 0) cout << ", ";
switch (parms[idx].type()) {
case vvm_calltf_parm::NONE:
break;
case vvm_calltf_parm::ULONG:
cout << parms[idx].as_ulong();
break;
case vvm_calltf_parm::STRING:
cout << "\"" << parms[idx].as_string() << "\"";
break;
case vvm_calltf_parm::BITS:
cout << *parms[idx].as_bits();
break;
case vvm_calltf_parm::TIME:
break;
}
extern "C" void vpi_sim_control(int func, ...)
{
switch (func) {
case vpiFinish:
vpi_sim->s_finish();
break;
}
cout << ")" << endl;
}
extern "C" vpiHandle vpi_handle(int type, vpiHandle ref)
{
switch (type) {
case vpiSysTfCall:
return vvm_vpi_cur_task;
default:
return 0;
}
}
extern "C" vpiHandle vpi_iterate(int type, vpiHandle ref)
{
vpiHandle res = (vpiHandle)calloc(1, sizeof (struct __vpiHandle));
res->type = type;
res->referent = ref;
res->val.unum = 0;
return res;
}
extern "C" vpiHandle vpi_scan(vpiHandle ref)
{
assert(ref->type == vpiArgument);
if (ref->val.unum >= ref->referent->narguments) {
vpi_free_object(ref);
return 0;
}
return ref->referent->arguments[ref->val.unum++];
}
extern "C" int vpi_get(int property, vpiHandle ref)
{
if (property == vpiType)
return ref->type;
if (ref->get_ == 0)
return -1;
return (ref->get_)(property, ref);
}
extern "C" char* vpi_get_str(int property, vpiHandle ref)
{
if (property == vpiFullName)
return ref->full_name;
if (ref->get_str_ == 0)
return 0;
return (ref->get_str_)(property, ref);
switch (property) {
case vpiName:
return ref->full_name;
}
return 0;
}
extern "C" void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
{
if (expr->get_value_) {
expr->get_value_(expr, vp);
return;
}
vp->format = vpiSuppressVal;
}
extern "C" int vpi_free_object(vpiHandle ref)
{
free(ref);
return 0;
}
/*
* This function is a get_value_ method of a vpiHandle, that supports
* reading bits as a string.
*/
static void get_value_bits(vpiHandle ref, s_vpi_value*vp)
{
static char buff[1024];
char*cp;
unsigned width, bytes;
unsigned val;
assert(ref->val.bits);
width = ref->val.bits->get_width();
cp = buff;
switch (vp->format) {
case vpiObjTypeVal:
case vpiBinStrVal:
for (unsigned idx = 0 ; idx < width ; idx += 1)
switch (ref->val.bits->get_bit(width-idx-1)) {
case V0:
*cp++ = '0';
break;
case V1:
*cp++ = '1';
break;
case Vx:
*cp++ = 'x';
break;
case Vz:
*cp++ = 'z';
break;
}
vp->format = vpiBinStrVal;
break;
case vpiDecStrVal:
val = 0;
for (unsigned idx = 0 ; idx < width ; idx += 1) {
val *= 2;
switch (ref->val.bits->get_bit(width-idx-1)) {
case V0:
case Vx:
case Vz:
break;
case V1:
val += 1;
break;
}
}
sprintf(cp, "%u", val);
cp += strlen(cp);
break;
case vpiOctStrVal:
bytes = width%3;
if (bytes) {
*cp++ = '?';
}
for (unsigned idx = bytes ; idx < width ; idx += 3) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
for (unsigned i = idx ; i < idx+3 ; i += 1) {
v *= 2;
switch (ref->val.bits->get_bit(width-idx-i-1)) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == 3)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == 3)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "01234567"[v];
}
break;
case vpiHexStrVal:
if (width%4) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
for (unsigned i = 0 ; i < width%4 ; i += 1) {
v *= 2;
switch (ref->val.bits->get_bit(width-i-1)) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == width%4)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == width%4)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "0123456789abcdef"[v];
}
for (unsigned idx = width%4 ; idx < width ; idx += 4) {
unsigned x = 0;
unsigned z = 0;
unsigned v = 0;
for (unsigned i = idx ; i < idx+4 ; i += 1) {
v *= 2;
switch (ref->val.bits->get_bit(width-i-1)) {
case V0:
break;
case V1:
v += 1;
break;
case Vx:
x += 1;
break;
case Vz:
z += 1;
break;
}
}
if (x == 4)
*cp++ = 'x';
else if (x > 0)
*cp++ = 'X';
else if (z == 4)
*cp++ = 'z';
else if (z > 0)
*cp++ = 'Z';
else
*cp++ = "0123456789abcdef"[v];
}
break;
default:
*cp++ = '(';
*cp++ = '?';
*cp++ = ')';
break;
}
*cp++ = 0;
vp->value.str = buff;
}
static void get_value_strconst(vpiHandle ref, s_vpi_value*vp)
{
switch (vp->format) {
case vpiObjTypeVal:
case vpiStringVal:
vp->value.str = ref->full_name;
vp->format = vpiStringVal;
break;
default:
vp->format = vpiSuppressVal;
break;
}
}
static void get_value_timevar(vpiHandle ref, s_vpi_value*vp)
{
static char buf[128];
switch (vp->format) {
case vpiObjTypeVal:
case vpiTimeVal:
vp->value.time = &ref->val.time;
vp->format = vpiTimeVal;
break;
case vpiDecStrVal:
sprintf(buf, "%u", ref->val.time.low);
vp->value.str = buf;
break;
default:
vp->format = vpiSuppressVal;
vp->value.str = 0;
break;
}
}
/*
* The load_vpi_module function attempts to locate and load the named
* vpi module and call the included startup routines. This is invoked
* by the generated C++ code to load all the modules that the
* simulation requires.
*
* If there is a '/' character in the name, or there is no
* VPI_MODULE_PATH, the the name is usd as is. No path is searched for
* the module.
*
* If there is a VPI_MODULE_PATH and there is no '/' in the name, the
* VPI_MODULE_PATH is taken as a ':' separated list of directory
* names. Each directory is searched for a module with the right name
* that will link in. The current working directory is not implicitly
* tried. If you wish '.' be in th search path, include it.
*/
typedef void (*vlog_startup_routines_t)(void);
void vvm_load_vpi_module(const char*name)
{
void*mod = 0;
const char*path = getenv("VPI_MODULE_PATH");
if ((path == 0) || (strchr(name, '/'))) {
mod = dlopen(name, RTLD_NOW);
if (mod == 0) {
cerr << name << ": " << dlerror() << endl;
return;
}
} else {
const char*cur = path;
const char*ep;
for (cur = path ; cur ; cur = ep? ep+1 : 0) {
char dest[MAX_PATHLEN+1];
ep = strchr(cur, ':');
size_t n = ep? ep-cur : strlen(cur);
if ((n + strlen(name) + 2) > sizeof dest)
continue;
strncpy(dest, cur, n);
dest[n] = '/';
dest[n+1] = 0;
strcat(dest, name);
mod = dlopen(dest, RTLD_NOW);
if (mod) break;
}
}
if (mod == 0) {
cerr << dlerror() << endl;
return;
}
void*table = dlsym(mod, "vlog_startup_routines");
vlog_startup_routines_t*routines = (vlog_startup_routines_t*)table;
if (routines == 0) {
cerr << name << ": Unable to locate the vlog_startup_routines"
" table." << endl;
dlclose(mod);
return;
}
for (unsigned idx = 0 ; routines[idx] ; idx += 1)
(routines[idx])();
}
void vvm_make_vpi_parm(vpiHandle ref, const char*val)
{
memset(ref, 0, sizeof*ref);
ref->type = vpiConstant;
ref->subtype = vpiStringConst;
ref->full_name = const_cast<char*>(val);
ref->get_value_ = &get_value_strconst;
}
void vvm_make_vpi_parm(vpiHandle ref, vvm_bits_t*val)
{
memset(ref, 0, sizeof*ref);
ref->type = vpiConstant;
ref->subtype = vpiBinaryConst;
ref->full_name = "";
ref->val.bits = val;
ref->get_value_ = &get_value_bits;
}
void vvm_init_vpi_handle(vpiHandle ref, vvm_bits_t*bits, vvm_monitor_t*mon)
{
memset(ref, 0, sizeof*ref);
ref->type = vpiReg;
ref->full_name = const_cast<char*>(mon->name());
ref->val.bits = bits;
ref->get_value_ = &get_value_bits;
}
void vvm_init_vpi_timevar(vpiHandle ref, const char*name)
{
memset(ref, 0, sizeof*ref);
ref->type = vpiTimeVar;
ref->full_name = const_cast<char*>(name);
ref->get_value_ = &get_value_timevar;
}
void vvm_make_vpi_parm(vpiHandle ref)
{
memset(ref, 0, sizeof*ref);
ref->type = 0;
}
void vvm_calltask(vvm_simulation*sim, const string&fname,
unsigned nparms, vpiHandle*parms)
{
vpi_sim = sim;
struct __vpiHandle cur_task;
cur_task.type = vpiSysTaskCall;
cur_task.full_name = 0;
cur_task.referent = 0;
cur_task.arguments = parms;
cur_task.narguments = nparms;
vvm_vpi_cur_task = &cur_task;
/* Look for a systf function to invoke. */
for (systf_entry*idx = systf_list ; idx ; idx = idx->next)
if (fname == idx->systf_data.tfname) {
cur_task.full_name = idx->systf_data.tfname;
idx->systf_data.calltf(idx->systf_data.user_data);
return;
}
/* Finally, if nothing is found then something is not
right. Print out the function name all the parameters
passed, so that someone can deal with it. */
cout << "Call " << fname << endl;
}
/*
* $Log: vvm_calltf.cc,v $
* Revision 1.6 1999/09/29 01:41:18 steve
* Support the $write system task, and have the
* vpi_scan function free iterators as needed.
*
* Revision 1.5 1999/09/13 03:08:10 steve
* fix vpiHexStrVal dumping of digits to strings.
*
* Revision 1.4 1999/08/19 02:51:11 steve
* Add vpi_sim_control
*
* Revision 1.3 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
* Revision 1.2 1999/05/31 15:46:36 steve
* Handle time in more places.
*
+30 -48
View File
@@ -19,69 +19,51 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_calltf.h,v 1.1 1998/11/09 23:44:11 steve Exp $"
#ident "$Id: vvm_calltf.h,v 1.2 1999/08/15 01:23:56 steve Exp $"
#endif
# include "vvm.h"
# include <string>
typedef struct __vpiHandle*vpiHandle;
/*
* This function loads a vpi module by name.
*/
extern void vvm_load_vpi_module(const char*path);
/*
* The vvm_init_vpi_handle functions initialize statis VPI handles
* that may be used many places within the program.
*/
extern void vvm_init_vpi_handle(vpiHandle, vvm_bits_t*, vvm_monitor_t*);
extern void vvm_init_vpi_timevar(vpiHandle, const char*name);
/*
* The vvm_make_vpi_parm functions initialize the vpiHandles to
* represent objects suitable for use as vvm_calltask parameters.
*/
extern void vvm_make_vpi_parm(vpiHandle ref, const char*val);
extern void vvm_make_vpi_parm(vpiHandle ref, vvm_bits_t*val);
extern void vvm_make_vpi_parm(vpiHandle ref);
/*
* The vvm environment supports external calls to C++ by
* vvm_calltask. The code generator generates calls to vvm_calltask
* that corresponds to the system call in the Verilog source. The
* vvm_calltask in turn locates the function (by name) and calls the
* C++ code that implements the task.
*
* The parameters of the task are implemented as an array of
* vvm_calltf_parm objects. Each object represents a paramter from the
* source.
* vvm_calltask in turn locates the vpi implementation (by name) and
* calls the VPI that implements the task.
*/
class vvm_calltf_parm {
public:
enum TYPE { NONE, ULONG, STRING, BITS, TIME };
vvm_calltf_parm();
explicit vvm_calltf_parm(TYPE);
vvm_calltf_parm(const vvm_calltf_parm&);
~vvm_calltf_parm();
TYPE type() const { return type_; }
struct SIG {
vvm_bits_t*bits;
vvm_monitor_t*mon;
};
unsigned long as_ulong() const { return ulong_; }
string as_string() const { return *(string*)string_; }
vvm_bits_t* as_bits() const { return bits_.bits; }
vvm_monitor_t* as_mon() const { return bits_.mon; }
const string& sig_name() const { return bits_.mon->name(); }
vvm_calltf_parm& operator= (unsigned long);
vvm_calltf_parm& operator= (const string&);
vvm_calltf_parm& operator= (const SIG&);
vvm_calltf_parm& operator= (const vvm_calltf_parm&);
private:
TYPE type_;
union {
unsigned long ulong_;
char string_[sizeof(string)];
SIG bits_;
};
void release_();
};
extern void vvm_calltask(vvm_simulation*sim, const string&name,
unsigned nparms, class vvm_calltf_parm*parms);
unsigned nparms, vpiHandle*parms);
/*
* $Log: vvm_calltf.h,v $
* Revision 1.2 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
+302 -3
View File
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_func.h,v 1.7 1999/06/24 04:20:47 steve Exp $"
#ident "$Id: vvm_func.h,v 1.14 1999/10/05 06:19:47 steve Exp $"
#endif
# include "vvm.h"
@@ -78,6 +78,13 @@ vvm_bitset_t<1> vvm_unop_or(const vvm_bitset_t<WIDTH>&r)
return res;
}
template <unsigned WIDTH>
vvm_bitset_t<1> vvm_unop_nor(const vvm_bitset_t<WIDTH>&r)
{
vvm_bitset_t<1>res = vvm_unop_or(r);
return vvm_unop_not(res);
}
template <unsigned WIDTH>
vvm_bitset_t<1> vvm_unop_lnot(const vvm_bitset_t<WIDTH>&r)
{
@@ -85,6 +92,44 @@ vvm_bitset_t<1> vvm_unop_lnot(const vvm_bitset_t<WIDTH>&r)
return vvm_unop_not(res);
}
/*
* The unary XOR is the reduction XOR. It returns a single bit.
*/
template <unsigned WIDTH>
vvm_bitset_t<1> vvm_unop_xor(const vvm_bitset_t<WIDTH>&r)
{
vvm_bitset_t<1> res;
res[0] = V0;
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) {
if (r[idx] == V1)
res[0] = not(res[0]);
}
return res;
}
template <unsigned WIDTH>
vvm_bitset_t<1> vvm_unop_xnor(const vvm_bitset_t<WIDTH>&r)
{
return not(vvm_unop_xor(r));
}
//
// simple-minded unary minus operator (two's complement)
//
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_unop_uminus(const vvm_bitset_t<WIDTH>&l)
{
vvm_bitset_t<WIDTH> res;
res = vvm_unop_not(l);
vvm_bit_t carry = V1;
for (int i = 0; i < WIDTH; i++)
res[i] = add_with_carry(res[i], V0, carry);
return res;
}
/*
* Implement the binary AND operator. This is a bitwise and with all
* the parameters and the result having the same width.
@@ -165,6 +210,40 @@ vvm_bitset_t<WIDTH> vvm_binop_xor(const vvm_bitset_t<WIDTH>&l,
return result;
}
/*
* the binary 'l' operator is a logic left-shift by the number of positions
* indicated by argument r. r is an unsigned integer, which is represented
* internally as a 32-bit bitvector.
*/
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_binop_shiftl(const vvm_bitset_t<WIDTH>&l,
const vvm_bitset_t<32>&r)
{
vvm_bitset_t<WIDTH> result;
vvm_u32 s = r.as_unsigned();
for (unsigned idx = 0; idx < WIDTH; idx++)
result[idx] = (idx < s) ? V0 : l[idx-s];
return result;
}
/*
* The binary 'r' operator is a logic right-shift by the number of positions
* indicated by argument r. r is an unsigned integer, which is represented
* internally by a 32-bit bitvector.
*/
template <unsigned WIDTH>
vvm_bitset_t<WIDTH> vvm_binop_shiftr(const vvm_bitset_t<WIDTH>&l,
const vvm_bitset_t<32>&r)
{
vvm_bitset_t<WIDTH> result;
vvm_u32 s = r.as_unsigned();
for (unsigned idx = 0; idx < WIDTH; idx++)
result[idx] = (idx < (WIDTH-s)) ? l[idx+s] : V0;
return result;
}
/*
* Tests for equality are a bit tricky, as they allow for the left and
* right subexpressions to have different size. The shorter bitset is
@@ -239,6 +318,10 @@ vvm_bitset_t<1> vvm_binop_eq(const vvm_bitset_t<LW>&l,
}
}
/*
* This function return true if all the bits are the same. Even x and
* z bites are compared for equality.
*/
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_eeq(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
@@ -277,6 +360,112 @@ vvm_bitset_t<1> vvm_binop_eeq(const vvm_bitset_t<LW>&l,
return result;
}
/*
* This function return true if all the bits are the same. The x and z
* bits are don't care, s don't make the result false.
*/
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_xeq(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V1;
if (LW <= RW) {
for (unsigned idx = 0 ; idx < LW ; idx += 1) {
if ((l[idx] == Vz) || (r[idx] == Vz))
continue;
if ((l[idx] == Vx) || (r[idx] == Vx))
continue;
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = LW ; idx < RW ; idx += 1) {
if ((r[idx] == Vx) || (r[idx] == Vz))
continue;
if (r[idx] != V0) {
result[0] = V0;
return result;
}
}
} else {
for (unsigned idx = 0 ; idx < RW ; idx += 1) {
if ((l[idx] == Vz) || (r[idx] == Vz))
continue;
if ((l[idx] == Vx) || (r[idx] == Vx))
continue;
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = RW ; idx < LW ; idx += 1) {
if ((l[idx] == Vx) || (l[idx] == Vz))
continue;
if (l[idx] != V0) {
result[0] = V0;
return result;
}
}
}
return result;
}
/*
* This function return true if all the bits are the same. The z
* bits are don't care, so don't make the result false.
*/
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_zeq(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V1;
if (LW <= RW) {
for (unsigned idx = 0 ; idx < LW ; idx += 1) {
if ((l[idx] == Vz) || (r[idx] == Vz))
continue;
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = LW ; idx < RW ; idx += 1) {
if (r[idx] == Vz)
continue;
if (r[idx] != V0) {
result[0] = V0;
return result;
}
}
} else {
for (unsigned idx = 0 ; idx < RW ; idx += 1) {
if ((l[idx] == Vz) || (r[idx] == Vz))
continue;
if (l[idx] != r[idx]) {
result[0] = V0;
return result;
}
}
for (unsigned idx = RW ; idx < LW ; idx += 1) {
if (l[idx] == Vz)
continue;
if (l[idx] != V0) {
result[0] = V0;
return result;
}
}
}
return result;
}
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_ne(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
@@ -299,12 +488,87 @@ template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_lt(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
assert(LW == RW);
vvm_bitset_t<1> result;
result[0] = V0;
for (unsigned idx = 0 ; idx < LW ; idx += 1)
const unsigned common = (LW < RW)? LW : RW;
for (unsigned idx = 0 ; idx < common ; idx += 1)
result[0] = less_with_cascade(l[idx], r[idx], result[0]);
if (LW > RW) {
for (unsigned idx = RW ; idx < LW ; idx += 1)
result[0] = less_with_cascade(l[idx], V0, result[0]);
} else {
for (unsigned idx = LW ; idx < RW ; idx += 1)
result[0] = less_with_cascade(V0, r[idx], result[0]);
}
return result;
}
/*
* The <= operator takes operands of natural width and returns a
* single bit. The result is V1 if l <= r, otherwise V0;
*/
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_le(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V1;
const unsigned common = (LW < RW)? LW : RW;
for (unsigned idx = 0 ; idx < common ; idx += 1)
result[0] = less_with_cascade(l[idx], r[idx], result[0]);
if (LW > RW) {
for (unsigned idx = RW ; idx < LW ; idx += 1)
result[0] = less_with_cascade(l[idx], V0, result[0]);
} else {
for (unsigned idx = LW ; idx < RW ; idx += 1)
result[0] = less_with_cascade(V0, r[idx], result[0]);
}
return result;
}
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_gt(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V0;
const unsigned common = (LW < RW)? LW : RW;
for (unsigned idx = 0 ; idx < common ; idx += 1)
result[0] = greater_with_cascade(l[idx], r[idx], result[0]);
if (LW > RW) {
for (unsigned idx = RW ; idx < LW ; idx += 1)
result[0] = greater_with_cascade(l[idx], V0, result[0]);
} else {
for (unsigned idx = LW ; idx < RW ; idx += 1)
result[0] = greater_with_cascade(V0, r[idx], result[0]);
}
return result;
}
template <unsigned LW, unsigned RW>
vvm_bitset_t<1> vvm_binop_ge(const vvm_bitset_t<LW>&l,
const vvm_bitset_t<RW>&r)
{
vvm_bitset_t<1> result;
result[0] = V1;
const unsigned common = (LW < RW)? LW : RW;
for (unsigned idx = 0 ; idx < common ; idx += 1)
result[0] = greater_with_cascade(l[idx], r[idx], result[0]);
if (LW > RW) {
for (unsigned idx = RW ; idx < LW ; idx += 1)
result[0] = greater_with_cascade(l[idx], V0, result[0]);
} else {
for (unsigned idx = LW ; idx < RW ; idx += 1)
result[0] = greater_with_cascade(V0, r[idx], result[0]);
}
return result;
}
@@ -328,8 +592,43 @@ vvm_bitset_t<1> vvm_binop_lor(const vvm_bitset_t<LW>&l,
return res1;
}
template <unsigned W>
vvm_bitset_t<W> vvm_ternary(vvm_bit_t c, const vvm_bitset_t<W>&t,
const vvm_bitset_t<W>&f)
{
switch (c) {
case V0:
return f;
case V1:
return t;
default:
return f;
}
}
/*
* $Log: vvm_func.h,v $
* Revision 1.14 1999/10/05 06:19:47 steve
* Add support for reduction NOR.
*
* Revision 1.13 1999/10/01 15:26:29 steve
* Add some vvm operators from Eric Aardoom.
*
* Revision 1.12 1999/09/29 22:57:26 steve
* LT supports different width objects.
*
* Revision 1.11 1999/09/29 18:36:04 steve
* Full case support
*
* Revision 1.10 1999/09/28 01:13:16 steve
* Support in vvm > and >= behavioral operators.
*
* Revision 1.9 1999/09/23 04:39:52 steve
* The <= operator takes different width operands.
*
* Revision 1.8 1999/09/11 04:43:17 steve
* Support ternary and <= operators in vvm.
*
* Revision 1.7 1999/06/24 04:20:47 steve
* Add !== and === operators.
*
+5 -2
View File
@@ -17,13 +17,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_monitor.cc,v 1.1 1998/11/09 23:44:11 steve Exp $"
#ident "$Id: vvm_monitor.cc,v 1.2 1999/08/15 01:23:56 steve Exp $"
#endif
# include "vvm.h"
vvm_monitor_t::vvm_monitor_t(const string&n)
vvm_monitor_t::vvm_monitor_t(const char*n)
: name_(n)
{
}
@@ -31,6 +31,9 @@ vvm_monitor_t::vvm_monitor_t(const string&n)
/*
* $Log: vvm_monitor.cc,v $
* Revision 1.2 1999/08/15 01:23:56 steve
* Convert vvm to implement system tasks with vpi.
*
* Revision 1.1 1998/11/09 23:44:11 steve
* Add vvm library.
*
+21 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: vvm_simulation.cc,v 1.4 1999/06/19 03:31:33 steve Exp $"
#ident "$Id: vvm_simulation.cc,v 1.6 1999/10/06 01:28:18 steve Exp $"
#endif
# include "vvm.h"
@@ -132,7 +132,7 @@ void vvm_simulation::run()
time_ += sim_->delay;
sim_->delay = 0;
for (;;) {
while (going_) {
/* Look for some events to make active. If the
main event list is empty, then activate the
nonblock list. */
@@ -150,7 +150,7 @@ void vvm_simulation::run()
if (active == 0)
break;
while (active) {
while (active && going_) {
vvm_event*cur = active;
active = cur->next_;
cur->event_function();
@@ -158,6 +158,12 @@ void vvm_simulation::run()
}
}
/* If the simulation was stopped by one of the events,
then break out of the loop before doing any monitor
events, and before clearing the current time. */
if (!going_)
break;
/* XXXX Execute monitor events here. */
if (mon_) {
mon_->event_function();
@@ -193,9 +199,13 @@ void vvm_simulation::s_finish()
going_ = false;
}
bool vvm_simulation::finished() const
{
return !going_;
}
void vvm_simulation::thread_delay(unsigned long delay, vvm_thread*thr)
{
assert(delay > 0);
delay_event*ev = new delay_event(thr);
insert_event(delay, ev);
}
@@ -209,6 +219,12 @@ void vvm_simulation::thread_active(vvm_thread*thr)
/*
* $Log: vvm_simulation.cc,v $
* Revision 1.6 1999/10/06 01:28:18 steve
* The $finish task should work immediately.
*
* Revision 1.5 1999/09/29 02:53:33 steve
* Useless assertion.
*
* Revision 1.4 1999/06/19 03:31:33 steve
* End run if events run out.
*
+92
View File
@@ -0,0 +1,92 @@
For those of you who wish to use Icarus Verilog, in combination with
the Xilinx back end (Foundation or Alliance), it can be done. I have
run some admittedly simple (no arithmetic, 600 equivalent gates) designs
through this setup, targeting a Spartan XCS10.
Verilog:
As of Icarus Verilog 19990814, you still can't have logic buried
in procedural (flip-flop) assignment. I use a hacked workaround
copy of ivl that allows 1-bit wide logic. The other approach
is to use temporary wires, assign them to the logic, and assign
the reg to that wire. For example, instead of
always @ (posedge Clk) Z = ~Q1 & ~Q2 & ~Q3 & ~Q4;
you can write
wire newZ;
assign newZ = ~Q1 & ~Q2 & ~Q3 & ~Q4;
always @ (posedge Clk) Z = newZ;
Procedural assignments have to be given one at a time, to be
"found" by xnfsyn. Say
always @ (posedge Clk) Y = newY;
always @ (posedge Clk) Z = newZ;
rather than
always @ (posedge Clk) begin
Y = newY;
Z = newZ;
end
I had reason to use a global clock net. I used this snippet of
Verilog code to make it happen:
primitive BUFG ( O, I );
output O;
input I;
table
0:0;
1:1;
endtable
endprimitive
$attribute(BUFG,"XNF-LCA","BUFG:O,I")
Oh, yes, you probably also want to choose I/O pins! Try this:
wire d1;
$attribute(d1, "PAD", "i45"); // input
wire vsync;
$attribute(vsync, "PAD", "o67"); // output
Running ivl:
The -F switches are important. The following order seems to robustly
generate valid XNF files:
-Fxnfio -Fnobufz -Fsigfold -Fxnfsyn
Generating .pcf files:
The ngdbuild step seems to lose pin placement information that ivl
puts in the XNF file. Use xnf2pcf to extract this information to
a .pcf file, which the Xilinx place-and-route software _will_ pay
attention to.
Running the Xilinx back end:
You can presumably use the GUI, but that doesn't fit in Makefiles :-).
Here is the command sequence in pseudo-shell-script:
ngdbuild -p $part $1.xnf $1.ngd
map -p $part -o map.ncd $1.ngd
xnf2pcf <$1.xnf >$1.pcf # see above
par -w -ol 2 -d 0 map.ncd $1.ncd $1.pcf
bitgen_flags = -g ConfigRate:SLOW -g TdoPin:PULLNONE -g DonePin:PULLUP \
-g CRC:enable -g StartUpClk:CCLK -g SyncToDone:no \
-g DoneActive:C1 -g OutputsActive:C3 -g GSRInactive:C4 \
-g ReadClk:CCLK -g ReadCapture:enable -g ReadAbort:disable
bitgen $1.ncd -l -w $bitgen_flags
The Xilinx software has diarrhea of the temp files (14, not including
.xnf, .pcf, .ngd, .ncd, and .bit), so this sequence is best done in a
dedicated directory. Note in particular that map.ncd is a generic name.
Downloading:
I use the XESS (http://www.xess.com/) XSP-10 development board, which
uses the PC parallel (printer) port for downloading and interaction
with the host. They made an old version of their download program
public domain, posted it at
http://www.xess.com/FPGA/xstools.zip ,
and now there is a Linux port at
ftp://ftp.microux.com/pub/pilotscope/xstools.tar.gz .
The above hints are based on my experience with Foundation 1.5 on NT
(gack) and Alliance 2.1i on Solaris. Your mileage may vary. Good luck!
- Larry Doolittle <[email protected]> August 19, 1999
+4 -1
View File
@@ -22,7 +22,7 @@ line. The code generator needs to know the type of part to generate
code for, so the ``-fpart=<type>'' flag is also needed. For example,
to generate code for the 4010E the command line might start out as:
ivl -txnf -fpart=4010e -Fxnfsyn -Fxnfio [...]
ivl -txnf -fpart=4010e -Fxnfsyn -Fsigfold -Fxnfio [...]
Icarus Verilog includes the functions ``xnfsyn'' and ``xnfio'' to
perform transformations and optimizations on the design before code is
@@ -83,6 +83,9 @@ IBUF, NOT gates cannot be absorbed as in the OPAD case.
$Log: xnf.txt,v $
Revision 1.4 1999/08/14 22:48:21 steve
Mention the sigfold function.
Revision 1.3 1999/07/22 02:05:20 steve
is_constant method for PEConcat.
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
# xnf2pcf
# Converts perfectly good EXT records from an XNF file to
# a .pcf file for the "par" step of the Xilinx toolchain.
# Why on earth is this needed? Oh, well, the joys of working
# with black-box-ware.
# Usage: xnf2pcf <design.xnf >design.pcf
# Refer to the resulting .pcf file in the invocation of "par", syntax:
# par [options] infile[.ncd] outfile pcf_file[.pcf]
# Tested (successfully!) with XNF from Icarus Verilog, see
# http://www.geda.seul.org/tools/verilog/index.html
# and Xilinx back end tools from Foundation 1.5
# Author: Larry Doolittle <[email protected]>
# Date: August 19, 1999
echo "SCHEMATIC START ;"
echo "SCHEMATIC END ;"
echo
awk '/^EXT/{gsub(",",""); printf("COMP \"%s\" LOCATE = SITE \"P%s\" ;\n", $2, $4)}'
+11 -5
View File
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT)
#ident "$Id: xnfsyn.cc,v 1.2 1999/07/18 21:17:51 steve Exp $"
#ident "$Id: xnfsyn.cc,v 1.3 1999/08/18 04:00:02 steve Exp $"
#endif
/*
@@ -136,13 +136,16 @@ void xnfsyn_f::proc_casn_(class Design*des)
// ... and the rval must be a simple signal.
NetESignal*sig = dynamic_cast<NetESignal*>(asn_->rval());
if (sig == 0)
if (sig == 0) {
cerr << "Noted complex rval in DFF, name " << asn_->name() <<
", not yet implemented" << endl;
return ;
}
// The signal and the assignment must be the same width...
assert(asn_->pin_count() == sig->pin_count());
// Geneate enough DFF objects to handle the entire width.
// Generate enough DFF objects to handle the entire width.
for (unsigned idx = 0 ; idx < asn_->pin_count() ; idx += 1) {
// XXXX FIXME: Objects need unique names!
@@ -170,7 +173,7 @@ void xnfsyn_f::proc_casn_(class Design*des)
}
/*
* The process si far has been matches as:
* The process so far has been matched as:
*
* always @(posedge nclk_) if ...;
* always @(negedge nclk_) if ...;
@@ -197,7 +200,7 @@ void xnfsyn_f::proc_ccon_(class Design*des)
if (ce->pin_count() != 1)
return;
// Geneate enough DFF objects to handle the entire width.
// Generate enough DFF objects to handle the entire width.
for (unsigned idx = 0 ; idx < asn_->pin_count() ; idx += 1) {
// XXXX FIXME: Objects need unique names!
@@ -233,6 +236,9 @@ void xnfsyn(Design*des)
/*
* $Log: xnfsyn.cc,v $
* Revision 1.3 1999/08/18 04:00:02 steve
* Fixup spelling and some error messages. <LRDoolittle@lbl.gov>
*
* Revision 1.2 1999/07/18 21:17:51 steve
* Add support for CE input to XNF DFF, and do
* complete cleanup of replaced design nodes.