Compare commits

...

130 Commits

Author SHA1 Message Date
steve 568924dcb5 Version stamp update 2006-10-04 17:08:59 +00:00
steve 33b3f7bdda Detect delay precision overflow. 2006-10-04 00:37:03 +00:00
steve 3a04e0a051 Fix a dangling reference to NetEParam objects in defparams. 2006-10-04 00:34:45 +00:00
steve 66ae377801 Snapshot v0.8.3 2006-10-03 21:34:40 +00:00
steve 898db57405 Describe the preconfigure steps. 2006-09-28 23:42:14 +00:00
steve 0fe45b5046 Fix host type detection in some configure scripts. 2006-09-22 03:29:02 +00:00
steve 20cfe99457 Fix left shift of small unsized constants. 2006-09-20 20:27:02 +00:00
steve 4ec8b38a5c Special handling of exploded memory arguments. 2006-09-15 23:56:05 +00:00
steve 79add47002 Build instruction typos and minor corrections. 2006-09-15 23:53:24 +00:00
steve c429f4c9a7 missing sig diagnostics. 2006-08-23 04:09:14 +00:00
steve 7f6a0b652a Do not count self as signifincant in nodangle. 2006-08-23 04:08:55 +00:00
steve 9f3f9154eb Fix missing sig on certain mux outputs.
Ignore condit statements (for synthesis) with no outputs.
2006-08-23 04:08:19 +00:00
steve 498fd06412 Add synthesis for casez statements. 2006-08-22 04:22:45 +00:00
steve 6d3b780791 Improve performance of unlink of heavily connected nexa. 2006-08-15 03:41:24 +00:00
steve a0ec981c50 Improved nexus management performance. 2006-08-08 02:17:48 +00:00
steve 930cd598a0 Typo clearing an event cell. 2006-08-06 18:09:42 +00:00
steve 77adab0f33 Remove excess PEString:: prefix for stubborn compilers. 2006-07-28 16:26:17 +00:00
steve 0e3768f829 Handle statement output override better in blocks. 2006-07-23 19:42:33 +00:00
steve 22884f2e64 Add support for full_case attribute. 2006-07-10 00:21:49 +00:00
steve 62da6aca28 Root dir variable does not include lib/ivl components. 2006-07-07 21:31:50 +00:00
steve 525ebddb0c Properly synthesize casex statements. 2006-07-02 00:50:15 +00:00
steve 521750c007 Fix ambiguity warnings. 2006-06-27 01:47:25 +00:00
steve 85d2833a62 Fix const/non-const warnings. 2006-06-27 01:37:14 +00:00
steve e2cc258283 Cure exit from main warning. 2006-06-27 01:33:17 +00:00
steve f09cf85c76 Fix unused var warning for mingw32 build. 2006-06-27 01:30:20 +00:00
steve c32de1dba0 Handle case where case output appears to be internal. 2006-06-26 00:05:46 +00:00
steve 628b866c36 Change Copyright tag to License. 2006-06-24 05:22:55 +00:00
steve 08dbe801c1 synthesis of NetCondit handles partial resets. 2006-06-23 03:49:46 +00:00
steve 101810df21 Handle simple memory addressing in expression synthesis. 2006-06-15 01:57:26 +00:00
steve 3877b636df synthesis for NetEBitSel. 2006-06-14 03:02:54 +00:00
steve 9d028a63f2 Remove redundant call to get_root_dir. 2006-06-14 03:01:49 +00:00
steve 35e5cea9df Add support for -Wunused warnings. 2006-06-12 00:16:50 +00:00
steve ec510071f1 Fix partial use of NetMux in sync condit statements. 2006-06-07 03:17:39 +00:00
steve 7413c533f6 Compilation warnings. 2006-06-02 23:42:48 +00:00
steve dde69cebb6 Handle condit clauses with unassigned outputs. 2006-06-01 03:01:48 +00:00
steve f942657ad5 NetESignal input is only selected bits. 2006-05-21 21:58:46 +00:00
steve fad1620828 Replace assertions with error messages. 2006-05-20 16:06:48 +00:00
steve a9931e7a58 Fix synthesis of l-value bit select in block. 2006-05-18 01:47:12 +00:00
steve 6cd4adb135 Fix synthesis of expressions with land of vectors. 2006-05-15 03:55:22 +00:00
steve 9643b86ab3 Update to use only Mingw for build. 2006-05-08 04:33:35 +00:00
steve 452eaeaea8 Handle memory assignments out of range during synthesis 2006-05-05 01:56:36 +00:00
steve 3a6e2df958 Fix uninitialized mem_lref_ member. 2006-05-02 02:00:15 +00:00
steve e73b7e2656 parse.cc and parse.h are made by the same steps. 2006-05-01 20:11:56 +00:00
steve 469ec11190 Merge fixes from devel tree. 2006-04-25 05:11:14 +00:00
steve e0bbfa512c Constant propagate addresses through NetRamDq read ports. 2006-04-23 04:26:13 +00:00
steve 94c9af2a5d Add cprop debugging. 2006-04-23 04:25:45 +00:00
steve 9f2e7df0ff vpp.conf is generated, so add it to cvsignore. 2006-04-23 02:44:29 +00:00
steve f02b2c9d7a Fix handling of exploded memories with partial or missing resets. 2006-04-16 19:26:37 +00:00
steve 058dac4290 Exploded memories accessed by constant indices. 2006-04-10 03:43:39 +00:00
steve ce4e21a962 Punt on set/reset if some sources are unconnected. 2006-04-01 01:37:58 +00:00
steve 065d6bc1e3 Add synth debug flag 2006-04-01 01:37:24 +00:00
steve 312d09dc1d Handle asynchronous demux/bit replacements. 2006-03-26 23:09:21 +00:00
steve faf7f30283 Add the .demux device. 2006-03-26 23:09:00 +00:00
steve 5d41e98c1f More installation directory flexibility. 2006-03-26 21:47:26 +00:00
steve 5e8330a4ff Better error messages when synthesis fails. 2006-03-18 18:43:21 +00:00
steve ef8964c65a Fix crash when memory exploding doesnot work 2006-03-16 05:40:18 +00:00
steve aa42ec381c Fix a spelling error in an error message. 2006-03-16 05:39:43 +00:00
steve c9d4aab9cb Right shifts really are allowed. 2006-03-16 05:39:20 +00:00
steve b8bc531f05 Fix the memsynth1 case. 2006-03-12 07:34:16 +00:00
steve 79cb8c883a Add support for negedge FFs by using attributes. 2006-02-25 05:03:28 +00:00
steve 27e633410c Add change callback to vpiMemory objects. 2006-02-19 16:57:31 +00:00
steve 7527c466ed Handle synthesis of FF vectors with l-value decoder. 2006-02-19 00:11:31 +00:00
steve 3ea1214160 More robust test for concat constant-ness. 2006-02-07 22:46:23 +00:00
steve 782542922d Detect nul arguments to concat expressions. 2006-02-07 22:45:54 +00:00
steve 1f8102c4dc Speed up processing of connect when one side is empty. 2006-01-27 02:05:46 +00:00
steve c4b34e8720 Document how the default statement handling works. 2006-01-27 01:58:53 +00:00
steve e494be7cbf Fix pin_Sel overrun. 2006-01-22 00:13:59 +00:00
steve eb0a78e9ce When mux has wide select but sparse choices, use 1hot translation. 2006-01-21 21:42:31 +00:00
steve e80138ec8c Restrict DFF to only one of Sset and Sclr. 2006-01-18 06:16:11 +00:00
steve 943316c6f6 Support DFF with synchronous inputs. 2006-01-18 06:15:45 +00:00
steve 52b8ed9077 Rework l-value handling to allow for more l-value type flexibility. 2006-01-18 01:23:23 +00:00
steve fc227aa3e1 Remember to set DLL= flag. 2006-01-14 20:13:38 +00:00
steve 41993815e9 Show synchronous set/clr of FF. 2006-01-14 20:13:22 +00:00
steve c5063f5d2f Case statement handles partial outputs. 2006-01-01 02:25:07 +00:00
steve f28aa11936 Allow for implicit case default in synchronous processes. 2006-01-01 01:30:39 +00:00
steve 3131fa68b7 Fix crashes caused bu synthesis of sqrt32.v. 2005-12-31 04:28:14 +00:00
steve def3809b3f Handle DFF definitions spread out within a block. 2005-12-19 01:13:47 +00:00
steve 3429c24a6a Properly fail when concat is not actually constant. 2005-12-18 21:06:01 +00:00
steve f47627d752 Fix missing outputs from synchronous conditionals to get out from in. 2005-12-15 02:38:51 +00:00
steve 9468f3d06f Handle both asynchronous set and reset. 2005-12-14 01:53:39 +00:00
steve b997de63a5 Account for sync vs async muxes. 2005-12-14 00:54:29 +00:00
steve f50f06ab4e Handle concatenations in l-values. 2005-12-10 04:26:32 +00:00
steve d5d03812cd Fix crash on block with assignments that assign lval to self. 2005-12-10 03:30:50 +00:00
steve b6d5a0675e Support constant concatenation of constants. 2005-12-07 03:28:44 +00:00
steve e63e830d62 Error messages for missing else clauses. 2005-12-07 02:14:37 +00:00
steve 74ca34bd82 Handle partial sets of conditional clauses. 2005-11-16 00:38:26 +00:00
steve c9d480028e Allow for block output to be set throughout the statements. 2005-11-13 22:28:48 +00:00
steve cc89ba66af Do not panic if case statement is nul. 2005-11-13 22:28:14 +00:00
steve 05e6d51004 Snapshot 0.8.2 2005-09-30 15:13:37 +00:00
steve ae583204e3 Snapshot 0.8.2 2005-09-30 15:01:44 +00:00
steve 018476f7cd More predictable ordering of items in NexusSet. 2005-09-25 23:30:31 +00:00
steve bfabeab6b9 Add Xilinx virtex as a reference EDIF device. 2005-09-25 16:35:36 +00:00
steve 4a3f1a3641 Attach line numbers to NetMux devices. 2005-09-11 02:56:37 +00:00
steve d97560caa7 Fix overly agressive constant propagation through MUX causing lost Z bits. 2005-09-11 02:50:51 +00:00
steve 393102d43a Evaluate magnitude compare with real operands. 2005-09-09 02:17:08 +00:00
steve 8e97a0e4d4 Support b1 edge in primitive tables. 2005-09-09 02:13:15 +00:00
steve 4ea789a2d7 More explicit internal error message. 2005-09-04 15:41:54 +00:00
steve 354f7ad920 More explicit internal error message. 2005-09-04 15:39:19 +00:00
steve f4a6206790 Handle b0 edges in primitives. 2005-09-04 15:33:19 +00:00
steve fd29ba3398 Reduce mux slices that are constant throughout range. 2005-08-28 22:00:39 +00:00
steve 44fbf60885 More thorough constant propagation through MUX devices. 2005-08-28 19:51:02 +00:00
steve a0d69113c3 More thorough constant propagation through MUX devices. 2005-08-28 19:50:03 +00:00
steve 86942ac592 Dump CMP_GE devices. 2005-08-28 17:37:28 +00:00
steve 075f9cbc4b Back-port edif_nexus_to_joint from tgt-edif. 2005-08-27 22:29:30 +00:00
steve 9dab368880 fix configure and build instructions for mingw build. 2005-08-27 22:19:37 +00:00
steve 5f6027fb66 Join cell0 and cell1 instances in LPM target. 2005-08-25 18:52:32 +00:00
steve 53156793fe Add support for implicit defaults in case and conditions. 2005-08-22 01:00:41 +00:00
steve 4644c220e8 Handle statements in blocks overriding previous statement outputs. 2005-08-21 22:49:54 +00:00
steve c30cd9afea Display NOR gates. 2005-08-21 22:27:57 +00:00
steve a8f45a18f0 Fix the comment in the EDIT header. 2005-08-21 22:25:51 +00:00
steve 6828e3e2ea Generate LPM for the CMP_EQ device. 2005-08-21 14:39:33 +00:00
steve 75eb372adf configure tgt-edif subdir. 2005-08-21 02:20:16 +00:00
steve 3b753fe52b Add the tgt-edif target. 2005-08-17 01:17:28 +00:00
steve 8c73fa7840 Fix compilation warnings/errors with newer compilers. 2005-08-13 00:45:53 +00:00
steve d310e656c7 Fix parse errors related to pr766. 2005-07-27 14:48:34 +00:00
steve 0510367b70 Fix compile errors with g++-4. 2005-07-06 22:41:34 +00:00
steve 3e11207a56 Fix gcc4 build issues. 2005-06-14 15:33:54 +00:00
steve 665f31271f popen must be matched by pclose. 2005-03-22 15:53:12 +00:00
steve 9a2b56675c Fix set_width to allow binary logical operands to be self determined. 2005-03-05 01:36:16 +00:00
steve c9f38f5ffa Improve distclean targets. 2005-02-23 18:40:23 +00:00
steve 5ea4152162 Spelling fixes from Larry. 2005-02-23 18:37:52 +00:00
steve 327c897d7e Spellig fixes. 2005-02-19 16:39:30 +00:00
steve 29ebe486b7 Fix multiple delete of an expression. 2005-02-19 16:38:14 +00:00
steve 4af0acb3be Fix (from Tony) for clock compression detection 2005-02-11 17:04:22 +00:00
steve 8435774c26 Fix evaluate of constants in netlist concatenation repeats. 2005-01-29 00:18:23 +00:00
steve 6172748c65 Add stub config files to CVS. 2005-01-28 18:30:11 +00:00
steve ca0ae9040a Add ability to compile real values into index registers. 2005-01-28 18:29:29 +00:00
steve d9cdbde3f6 More robust handling of file name argument to $fopen. 2005-01-01 20:07:41 +00:00
steve 307a97116f Fix leak of word registers in code generator. 2004-12-12 04:25:10 +00:00
steve 83d2c6dfd1 Update for 0.8 files. 2004-10-14 01:12:41 +00:00
137 changed files with 10957 additions and 1065 deletions

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: LineInfo.cc,v 1.4 2003/01/17 05:49:03 steve Exp $"
#ident "$Id: LineInfo.cc,v 1.4.2.1 2005/08/13 00:45:53 steve Exp $"
#endif
# include "config.h"
@ -34,12 +34,12 @@ LineInfo::~LineInfo()
{
}
string LineInfo::get_line() const
std::string LineInfo::get_line() const
{
ostringstream buf;
std::ostringstream buf;
buf << (file_? file_ : "") << ":" << lineno_;
string res = buf.str();
std::string res = buf.str();
return res;
}
@ -61,6 +61,9 @@ void LineInfo::set_lineno(unsigned n)
/*
* $Log: LineInfo.cc,v $
* Revision 1.4.2.1 2005/08/13 00:45:53 steve
* Fix compilation warnings/errors with newer compilers.
*
* Revision 1.4 2003/01/17 05:49:03 steve
* Use stringstream in place of sprintf.
*

View File

@ -19,11 +19,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: LineInfo.h,v 1.7 2003/01/17 05:49:03 steve Exp $"
#ident "$Id: LineInfo.h,v 1.7.2.2 2005/08/13 00:45:53 steve Exp $"
#endif
# include <string>
using namespace std;
/*
* This class holds line information for an internal object.
*
@ -38,7 +40,7 @@ class LineInfo {
LineInfo();
~LineInfo();
string get_line() const;
std::string get_line() const;
void set_line(const LineInfo&that);
@ -52,6 +54,12 @@ class LineInfo {
/*
* $Log: LineInfo.h,v $
* Revision 1.7.2.2 2005/08/13 00:45:53 steve
* Fix compilation warnings/errors with newer compilers.
*
* Revision 1.7.2.1 2005/06/14 15:33:54 steve
* Fix gcc4 build issues.
*
* Revision 1.7 2003/01/17 05:49:03 steve
* Use stringstream in place of sprintf.
*

View File

@ -16,7 +16,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.169 2004/10/13 22:01:34 steve Exp $"
#ident "$Id: Makefile.in,v 1.169.2.5 2006/10/04 17:08:59 steve Exp $"
#
#
SHELL = /bin/sh
@ -25,7 +25,7 @@ SHELL = /bin/sh
# by the compiler. It reflects the assigned version number for the
# product as a whole. Most components also print the CVS Name: token
# in order to get a more automatic version stamp as well.
VERSION = 0.8
VERSION = 0.8.3
prefix = @prefix@
exec_prefix = @exec_prefix@
@ -54,6 +54,8 @@ INSTALL_DATA = @INSTALL_DATA@
STRIP = @STRIP@
LEX = @LEX@
YACC = @YACC@
MAN = @MAN@
PS2PDF = @PS2PDF@
CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) @CPPFLAGS@
CXXFLAGS = -Wall @CXXFLAGS@
@ -103,6 +105,7 @@ distclean: clean
for dir in vpi ivlpp tgt-verilog tgt-stub driver; \
do (cd $$dir ; $(MAKE) $@); done
rm -f Makefile config.status config.log config.cache config.h
rm -rf autom4te.cache
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o t-xnf.o
FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o xnfio.o
@ -169,10 +172,8 @@ lexor.o: lexor.cc parse.h
parse.o: parse.cc
parse.cc: $(srcdir)/parse.y
parse.cc parse.h: $(srcdir)/parse.y
$(YACC) --verbose -t -p VL -d -o parse.cc $(srcdir)/parse.y
parse.h: parse.cc
mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h
syn-rules.cc: $(srcdir)/syn-rules.y
@ -187,15 +188,25 @@ lexor_keyword.cc: lexor_keyword.gperf
gperf -o -i 7 -C -k 1-3,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
iverilog-vpi.ps: $(srcdir)/iverilog-vpi.man
man -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
$(MAN) -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
iverilog-vpi.pdf: iverilog-vpi.ps
ps2pdf iverilog-vpi.ps iverilog-vpi.pdf
$(PS2PDF) iverilog-vpi.ps iverilog-vpi.pdf
# Build and install the iverilog-vpi.pdf only if there is a man
# program *and* a ps2pdf program.
ifeq (@WIN32@,yes)
ifeq ($(MAN),none)
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
else
ifeq ($(PS2PDF),none)
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
else
INSTALL_DOC = $(prefix)/iverilog-vpi.pdf $(mandir)/man1/iverilog-vpi.1
INSTALL_DOCDIR = $(mandir)/man1
all: dep iverilog-vpi.pdf
endif
endif
INSTALL_DOCDIR = $(mandir)/man1
else
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
INSTALL_DOCDIR = $(mandir)/man1

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PDelays.cc,v 1.11 2003/06/21 01:21:42 steve Exp $"
#ident "$Id: PDelays.cc,v 1.11.2.1 2006/10/04 00:37:03 steve Exp $"
#endif
# include "config.h"
@ -72,6 +72,20 @@ static unsigned long calculate_val(Design*des, NetScope*scope,
dex = tmp;
}
int shift = scope->time_unit() - des->get_precision();
if (sizeof(unsigned) <= 4 && shift > 9) {
cerr << expr->get_line() << ": error: Precision overflow"
<< " in scope " << scope->name() << "." << endl;
cerr << expr->get_line() << ": :"
<< " Units are 10e" << scope->time_unit()
<< " minus precision 10e" << des->get_precision()
<< " is 10e" << shift << "." << endl;
cerr << expr->get_line() << ": : Perhaps a timescale "
<< "is missing or incorrect?" << endl;
des->errors += 1;
return 0;
}
/* If the delay expression is a real constant or vector
constant, then evaluate it, scale it to the local time
units, and return an adjusted value. */
@ -79,7 +93,6 @@ static unsigned long calculate_val(Design*des, NetScope*scope,
if (NetECReal*tmp = dynamic_cast<NetECReal*>(dex)) {
verireal fn = tmp->value();
int shift = scope->time_unit() - des->get_precision();
long delay = fn.as_long(shift);
if (delay < 0)
delay = 0;
@ -146,6 +159,9 @@ void PDelays::eval_delays(Design*des, NetScope*scope,
/*
* $Log: PDelays.cc,v $
* Revision 1.11.2.1 2006/10/04 00:37:03 steve
* Detect delay precision overflow.
*
* Revision 1.11 2003/06/21 01:21:42 steve
* Harmless fixup of warnings.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PExpr.cc,v 1.35 2004/10/04 01:10:51 steve Exp $"
#ident "$Id: PExpr.cc,v 1.35.2.1 2006/02/07 22:46:23 steve Exp $"
#endif
# include "config.h"
@ -90,6 +90,8 @@ bool PEConcat::is_constant(Module *mod) const
{
bool constant = repeat_? repeat_->is_constant(mod) : true;
for (unsigned i = 0; constant && i < parms_.count(); ++i) {
if (parms_[i] == 0)
continue;
constant = constant && parms_[i]->is_constant(mod);
}
return constant;
@ -262,6 +264,9 @@ bool PEUnary::is_constant(Module*m) const
/*
* $Log: PExpr.cc,v $
* Revision 1.35.2.1 2006/02/07 22:46:23 steve
* More robust test for concat constant-ness.
*
* Revision 1.35 2004/10/04 01:10:51 steve
* Clean up spurious trailing white space.
*

12
PExpr.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PExpr.h,v 1.66 2004/10/04 01:10:51 steve Exp $"
#ident "$Id: PExpr.h,v 1.66.2.2 2006/07/28 16:26:17 steve Exp $"
#endif
# include <string>
@ -115,6 +115,8 @@ class PEConcat : public PExpr {
PEConcat(const svector<PExpr*>&p, PExpr*r =0);
~PEConcat();
virtual verinum* eval_const(const Design*des, const NetScope*sc) const;
virtual void dump(ostream&) const;
// Concatenated Regs can be on the left of procedural
@ -324,7 +326,7 @@ class PEString : public PExpr {
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
bool sys_task_arg =false) const;
virtual NetEConst*elaborate_pexpr(Design*des, NetScope*sc) const;
verinum* PEString::eval_const(const Design*, const NetScope*) const;
verinum* eval_const(const Design*, const NetScope*) const;
virtual bool is_constant(Module*) const;
@ -492,6 +494,12 @@ class PECallFunction : public PExpr {
/*
* $Log: PExpr.h,v $
* Revision 1.66.2.2 2006/07/28 16:26:17 steve
* Remove excess PEString:: prefix for stubborn compilers.
*
* Revision 1.66.2.1 2005/12/07 03:28:44 steve
* Support constant concatenation of constants.
*
* Revision 1.66 2004/10/04 01:10:51 steve
* Clean up spurious trailing white space.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PTask.h,v 1.13 2004/05/31 23:34:36 steve Exp $"
#ident "$Id: PTask.h,v 1.13.2.1 2005/08/13 00:45:53 steve Exp $"
#endif
# include "LineInfo.h"
@ -70,7 +70,7 @@ class PTask : public LineInfo {
// Elaborate the statement to finish off the task definition.
void elaborate(Design*des, NetScope*scope) const;
void dump(ostream&, unsigned) const;
void dump(std::ostream&, unsigned) const;
private:
svector<PWire*>*ports_;
@ -106,7 +106,7 @@ class PFunction : public LineInfo {
/* Elaborate the behavioral statement. */
void elaborate(Design *des, NetScope*) const;
void dump(ostream&, unsigned) const;
void dump(std::ostream&, unsigned) const;
private:
perm_string name_;
@ -117,6 +117,9 @@ class PFunction : public LineInfo {
/*
* $Log: PTask.h,v $
* Revision 1.13.2.1 2005/08/13 00:45:53 steve
* Fix compilation warnings/errors with newer compilers.
*
* Revision 1.13 2004/05/31 23:34:36 steve
* Rewire/generalize parsing an elaboration of
* function return values to allow for better

13
PUdp.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PUdp.h,v 1.12 2004/03/08 00:47:44 steve Exp $"
#ident "$Id: PUdp.h,v 1.12.2.1 2005/08/13 00:45:53 steve Exp $"
#endif
# include <map>
@ -55,20 +55,20 @@ class PUdp {
public:
explicit PUdp(perm_string n, unsigned nports);
svector<string>ports;
svector<std::string>ports;
unsigned find_port(const char*name);
bool sequential;
svector<string>tinput;
svector<std::string>tinput;
svector<char> tcurrent;
svector<char> toutput;
verinum::V initial;
map<string,PExpr*> attributes;
std::map<std::string,PExpr*> attributes;
void dump(ostream&out) const;
void dump(std::ostream&out) const;
perm_string name_;
private:
@ -80,6 +80,9 @@ class PUdp {
/*
* $Log: PUdp.h,v $
* Revision 1.12.2.1 2005/08/13 00:45:53 steve
* Fix compilation warnings/errors with newer compilers.
*
* Revision 1.12 2004/03/08 00:47:44 steve
* primitive ports can bind bi name.
*

View File

@ -114,7 +114,7 @@ configure script that modify its behavior:
If you are building for Linux/AMD64 (a.k.a x86_64) then to get the
most out of your install, first make sure you have both 64bit and
32bit development libraries installed. Then configure with this
somewhat more compilcated command:
somewhat more complex command:
./configure libdir64='$(prefix)/lib64' vpidir1=vpi64 vpidir2=. --enable-vvp32

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: Statement.h,v 1.40 2004/02/20 18:53:33 steve Exp $"
#ident "$Id: Statement.h,v 1.40.2.1 2006/07/10 00:21:49 steve Exp $"
#endif
# include <string>
@ -71,12 +71,15 @@ class PProcess : public LineInfo {
* fact, the Statement class is abstract and represents all the
* possible kinds of statements that exist in Verilog.
*/
class Statement : public LineInfo {
class Statement : public LineInfo, public Attrib {
public:
Statement() { }
virtual ~Statement() =0;
map<perm_string,PExpr*> attributes;
void dump_attributes(ostream&out, unsigned ind) const;
virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const;
@ -456,6 +459,9 @@ class PWhile : public Statement {
/*
* $Log: Statement.h,v $
* Revision 1.40.2.1 2006/07/10 00:21:49 steve
* Add support for full_case attribute.
*
* Revision 1.40 2004/02/20 18:53:33 steve
* Addtrbute keys are perm_strings.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: StringHeap.cc,v 1.6 2004/02/18 17:11:54 steve Exp $"
#ident "$Id: StringHeap.cc,v 1.6.2.1 2005/08/13 00:45:53 steve Exp $"
#endif
# include "StringHeap.h"
@ -131,7 +131,7 @@ perm_string StringHeapLex::make(const char*text)
return perm_string(add(text));
}
perm_string StringHeapLex::make(const string&text)
perm_string StringHeapLex::make(const std::string&text)
{
return perm_string(add(text.c_str()));
}
@ -181,6 +181,9 @@ bool operator < (perm_string a, perm_string b)
/*
* $Log: StringHeap.cc,v $
* Revision 1.6.2.1 2005/08/13 00:45:53 steve
* Fix compilation warnings/errors with newer compilers.
*
* Revision 1.6 2004/02/18 17:11:54 steve
* Use perm_strings for named langiage items.
*

View File

@ -19,12 +19,14 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: StringHeap.h,v 1.5 2004/02/18 17:11:54 steve Exp $"
#ident "$Id: StringHeap.h,v 1.5.2.2 2005/08/13 00:45:53 steve Exp $"
#endif
# include "config.h"
# include <string>
using namespace std;
class perm_string {
public:
@ -101,7 +103,7 @@ class StringHeapLex : private StringHeap {
const char*add(const char*);
perm_string make(const char*);
perm_string make(const string&);
perm_string make(const std::string&);
unsigned add_count() const;
unsigned add_hit_count() const;
@ -120,6 +122,12 @@ class StringHeapLex : private StringHeap {
/*
* $Log: StringHeap.h,v $
* Revision 1.5.2.2 2005/08/13 00:45:53 steve
* Fix compilation warnings/errors with newer compilers.
*
* Revision 1.5.2.1 2005/06/14 15:33:54 steve
* Fix gcc4 build issues.
*
* Revision 1.5 2004/02/18 17:11:54 steve
* Use perm_strings for named langiage items.
*

18
aclocal.m4 vendored
View File

@ -14,7 +14,7 @@
AC_DEFUN([AX_CPP_IDENT],
[AC_CACHE_CHECK([for ident support in C compiler], ax_cv_cpp_ident,
[AC_TRY_COMPILE([
#ident "$Id: aclocal.m4,v 1.6 2004/10/04 01:10:52 steve Exp $"
#ident "$Id: aclocal.m4,v 1.6.2.1 2005/08/27 22:19:37 steve Exp $"
],[while (0) {}],
[AS_VAR_SET(ax_cv_cpp_ident, yes)],
[AS_VAR_SET(ax_cv_cpp_ident, no)])])
@ -91,13 +91,9 @@ AC_MSG_RESULT($WIN32)
AC_DEFUN([AX_LD_EXTRALIBS],
[AC_MSG_CHECKING([for extra libs needed])
EXTRALIBS=
case "${host}" in
*-*-cygwin* )
if test "$MINGW32" = "yes"; then
EXTRALIBS="-liberty"
fi
;;
esac
if test "$MINGW32" = "yes"; then
EXTRALIBS="-liberty"
fi
AC_SUBST(EXTRALIBS)
AC_MSG_RESULT($EXTRALIBS)
])# AX_LD_EXTRALIBS
@ -109,7 +105,7 @@ AC_DEFUN([AX_LD_SHAREDLIB_OPTS],
[AC_MSG_CHECKING([for shared library link flag])
shared=-shared
case "${host}" in
*-*-cygwin*)
*-*-cygwin* | *-*-mingw32*)
shared="-shared -Wl,--enable-auto-image-base"
;;
@ -138,7 +134,7 @@ AC_DEFUN([AX_C_PICFLAG],
PICFLAG=-fPIC
case "${host}" in
*-*-cygwin*)
*-*-cygwin* | *-*-mingw32*)
PICFLAG=
;;
@ -173,7 +169,7 @@ case "${host}" in
rdynamic=""
;;
*-*-cygwin*)
*-*-cygwin* | *-*-mingw32*)
rdynamic=""
;;

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: async.cc,v 1.7 2004/01/18 23:26:54 steve Exp $"
#ident "$Id: async.cc,v 1.7.2.1 2006/05/21 21:58:46 steve Exp $"
#endif
# include "config.h"
@ -66,6 +66,10 @@ bool NetEvWait::is_asynchronous()
NexusSet*inputs = statement_->nex_input();
/* All the inputs of the statement must be accounted for in
the sensitivity list. Otherwise, there are inputs that can
change without the event being triggered, and that implies
a latch, not a combinational circuit. */
if (! sense->contains(*inputs)) {
delete sense;
delete inputs;
@ -95,6 +99,9 @@ bool NetProcTop::is_asynchronous()
/*
* $Log: async.cc,v $
* Revision 1.7.2.1 2006/05/21 21:58:46 steve
* NetESignal input is only selected bits.
*
* Revision 1.7 2004/01/18 23:26:54 steve
* The is_combinational function really need not recurse.
*

View File

@ -70,6 +70,14 @@ warning.)
* Other Attributes
(* ivl_full_case *)
This attribute only has meaning when attached to case statements,
and only when doing synthesis. The statement means to ignore the
possibility that some cases are not defined. Presume that the
device really is fully specified and do not emit any warnings
about missing guards.
[ none defined yet ]

View File

@ -9,10 +9,10 @@
echo "Autoconf in root..."
autoconf
for dir in vpip vpi vvp tgt-vvp tgt-fpga libveriuser cadpli
for dir in vpip vpi vvp tgt-vvp tgt-edif tgt-fpga libveriuser cadpli
do
echo "Autoconf in $dir..."
( cd ./$dir ; autoconf --include=.. )
( cd ./$dir ; autoconf -f --include=.. )
done
echo "Precompiling lexor_keyword.gperf"

View File

@ -16,7 +16,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.11 2004/10/04 01:09:07 steve Exp $"
#ident "$Id: Makefile.in,v 1.11.2.1 2005/02/23 18:40:23 steve Exp $"
#
#
SHELL = /bin/sh
@ -86,6 +86,7 @@ clean:
distclean: clean
rm -f Makefile config.status config.log config.cache
rm -rf autom4te.cache
install: all installdirs $(vpidir)/cadpli.vpl $(INSTALL32)

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: compiler.h,v 1.26 2004/10/04 01:10:52 steve Exp $"
#ident "$Id: compiler.h,v 1.26.2.3 2006/06/12 00:16:50 steve Exp $"
#endif
# include <list>
@ -78,12 +78,17 @@ extern bool warn_timescale;
/* Warn about legal but questionable module port bindings. */
extern bool warn_portbinding;
/* Warn about unused or unassigned variables. */
extern bool warn_unused;
/* This is true if verbose output is requested. */
extern bool verbose_flag;
extern bool debug_scopes;
extern bool debug_eval_tree;
extern bool debug_elaborate;
extern bool debug_synth;
extern bool debug_cprop;
/* Path to a directory useful for finding subcomponents. */
extern const char*basedir;
@ -136,6 +141,15 @@ extern int load_sys_func_table(const char*path);
/*
* $Log: compiler.h,v $
* Revision 1.26.2.3 2006/06/12 00:16:50 steve
* Add support for -Wunused warnings.
*
* Revision 1.26.2.2 2006/04/23 04:25:45 steve
* Add cprop debugging.
*
* Revision 1.26.2.1 2006/04/01 01:37:24 steve
* Add synth debug flag
*
* Revision 1.26 2004/10/04 01:10:52 steve
* Clean up spurious trailing white space.
*

View File

@ -9,6 +9,9 @@ AC_PROG_CC
AC_PROG_CXX
AC_CHECK_TOOL(STRIP, strip, true)
AC_CHECK_PROGS(XGPERF,gperf,none)
AC_CHECK_PROGS(MAN,man,none)
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
if test "$XGPERF" = "none"
then
echo ""
@ -141,6 +144,6 @@ AC_SUBST(vpidir1)
AC_SUBST(vpidir2)
AC_MSG_RESULT(${vpidir1} ${vpidir2})
AC_CONFIG_SUBDIRS(vvp vpi tgt-vvp tgt-fpga libveriuser cadpli)
AC_CONFIG_SUBDIRS(vvp vpi tgt-vvp tgt-edif tgt-fpga libveriuser cadpli)
AC_OUTPUT(Makefile ivlpp/Makefile driver/Makefile driver-vpi/Makefile tgt-null/Makefile tgt-stub/Makefile tgt-verilog/Makefile tgt-pal/Makefile)

378
cprop.cc
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2006 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
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: cprop.cc,v 1.47 2004/02/20 18:53:34 steve Exp $"
#ident "$Id: cprop.cc,v 1.47.2.5 2006/04/23 04:26:13 steve Exp $"
#endif
# include "config.h"
@ -25,6 +25,7 @@
# include "netlist.h"
# include "netmisc.h"
# include "functor.h"
# include "compiler.h"
# include <assert.h>
@ -47,6 +48,9 @@ struct cprop_functor : public functor_t {
virtual void lpm_ff(Design*des, NetFF*obj);
virtual void lpm_logic(Design*des, NetLogic*obj);
virtual void lpm_mux(Design*des, NetMux*obj);
virtual void lpm_mux_large(Design*des, NetMux*obj);
virtual void lpm_ram_dq(Design*des, NetRamDq*obj);
bool lpm_ram_dq_const_address_(Design*des, NetRamDq*obj);
};
void cprop_functor::signal(Design*des, NetNet*obj)
@ -847,79 +851,353 @@ void cprop_functor::lpm_logic(Design*des, NetLogic*obj)
*/
void cprop_functor::lpm_mux(Design*des, NetMux*obj)
{
if (obj->size() > 2) {
lpm_mux_large(des, obj);
return;
}
if (obj->size() != 2)
return;
if (obj->sel_width() != 1)
return;
/* If the first input is all constant Vz, then replace the
NetMux with an array of BUFIF1 devices, with the enable
connected to the select input. */
NetScope*scope = obj->scope();
bool flag = true;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (! obj->pin_Data(idx, 0).nexus()->drivers_constant()) {
flag = false;
break;
}
bool cflag_a = obj->pin_Data(idx, 0).nexus()->drivers_constant();
bool cflag_b = obj->pin_Data(idx, 1).nexus()->drivers_constant();
if (obj->pin_Data(idx, 0).nexus()->driven_value() != verinum::Vz) {
flag = false;
break;
}
/* If both data inputs are constant, we'll be able to do
a substitution. */
if (cflag_a && cflag_b)
continue;
verinum::V va = cflag_a
? obj->pin_Data(idx, 0).nexus()->driven_value()
: verinum::Vx;
verinum::V vb = cflag_b
? obj->pin_Data(idx, 1).nexus()->driven_value()
: verinum::Vx;
/* If only one Data input is constant, but a constant
HiZ, then we will be able to to a bufif
substitution. */
if (cflag_a && va==verinum::Vz)
continue;
if (cflag_b && vb==verinum::Vz)
continue;
/* Otherwise, we cannot accurately do a substitution. If
one input is non-constant, then that input may have a
HiZ value, and there is no Verilog logic other then a
MUX that can pass a HiZ value. */
flag = false;
}
if (flag) {
NetScope*scope = obj->scope();
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
NetLogic*tmp = new NetLogic(obj->scope(),
if (! flag) {
return;
}
/* We know that every slice has at least one constant. Run
through the slices again, creating boolean devices to
replace the MUX slice. */
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
/* If the Sel==0 input is constant Z, make a bufif1. */
if (obj->pin_Data(idx, 0).nexus()->drivers_constant()
&& obj->pin_Data(idx, 0).nexus()->driven_value()==verinum::Vz) {
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::BUFIF1);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
count += 1;
delete obj;
return;
}
/* If the Sel==1 input is constant Z, make a bufif0. */
if (obj->pin_Data(idx, 1).nexus()->drivers_constant()
&& obj->pin_Data(idx, 1).nexus()->driven_value()==verinum::Vz) {
/* If instead the second input is all constant Vz, replace the
NetMux with an array of BUFIF0 devices. */
flag = true;
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
if (! obj->pin_Data(idx, 1).nexus()->drivers_constant()) {
flag = false;
break;
}
if (obj->pin_Data(idx, 1).nexus()->driven_value() != verinum::Vz) {
flag = false;
break;
}
}
if (flag) {
NetScope*scope = obj->scope();
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
NetLogic*tmp = new NetLogic(obj->scope(),
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::BUFIF0);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,0), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
count += 1;
delete obj;
/* At this point, the only cases that are left are where
the data inputs are both constant, and neither are
HiZ. From this we know how to generate the output
from only the S input. */
assert(obj->pin_Data(idx, 0).nexus()->drivers_constant()
&& obj->pin_Data(idx, 1).nexus()->drivers_constant());
verinum::V a = obj->pin_Data(idx, 0).nexus()->driven_value();
verinum::V b = obj->pin_Data(idx, 1).nexus()->driven_value();
if (a == b) {
connect(obj->pin_Result(idx), obj->pin_Data(idx,0));
continue;
}
if (a == verinum::V0 && b == verinum::V1) {
connect(obj->pin_Result(idx), obj->pin_Sel(0));
continue;
}
if (a == verinum::V1 && b == verinum::V0) {
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
2, NetLogic::NOT);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Sel(0), tmp->pin(1));
des->add_node(tmp);
continue;
}
/* A==0: Q = B & S */
if (a == verinum::V0) {
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::AND);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
/* B==1: Q = A | S */
if (b == verinum::V1) {
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::OR);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,0), tmp->pin(1));
connect(obj->pin_Sel(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
/* A==1: Q = B | ~S */
if (a == verinum::V1) {
NetLogic*inv = new NetLogic(scope,
scope->local_symbol(),
2, NetLogic::NOT);
NetNet*invs = new NetNet(scope,
scope->local_symbol(),
NetNet::TRI, 1);
invs->local_flag(true);
connect(inv->pin(0), invs->pin(0));
connect(inv->pin(1), obj->pin_Sel(0));
des->add_node(inv);
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::OR);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,1), tmp->pin(1));
connect(inv->pin(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
/* B==0: Q = A & ~S */
if (b == verinum::V0) {
NetLogic*inv = new NetLogic(scope,
scope->local_symbol(),
2, NetLogic::NOT);
NetNet*invs = new NetNet(scope,
scope->local_symbol(),
NetNet::TRI, 1);
invs->local_flag(true);
connect(inv->pin(0), invs->pin(0));
connect(inv->pin(1), obj->pin_Sel(0));
des->add_node(inv);
NetLogic*tmp = new NetLogic(scope,
scope->local_symbol(),
3, NetLogic::AND);
connect(obj->pin_Result(idx), tmp->pin(0));
connect(obj->pin_Data(idx,0), tmp->pin(1));
connect(inv->pin(0), tmp->pin(2));
des->add_node(tmp);
continue;
}
assert(0);
}
delete obj;
count += 1;
}
void cprop_functor::lpm_mux_large(Design*des, NetMux*obj)
{
NetScope*scope = obj->scope();
unsigned width = obj->width();
unsigned size = obj->size();
/* This test looks for bit slices that are constant
throughout. If we find any, we can reduce the width of the
MUX to eliminate the fixed value. */
/* After the following for look, this array of bools will
contain "true" for each bit slice that is constant and
identical, and "false" otherwise. The reduce_width will
count the number of true entries in the flags array. */
bool*flags = new bool[width];
unsigned reduce_width = 0;
for (unsigned bit = 0 ; bit < width ; bit += 1) {
flags[bit] = true;
/* If not even the first selection is constant, then the
slice cannot be reduced. */
if (! obj->pin_Data(bit, 0).nexus()->drivers_constant()) {
flags[bit] = false;
continue;
}
/* If any of the remaining selections in non-consant, or
constant with a different value, then this slice
cannot be reduced. */
verinum::V val = obj->pin_Data(bit, 0).nexus()->driven_value();
for (unsigned idx = 1; flags[bit] && idx < size ; idx += 1) {
if (!obj->pin_Data(bit,idx).nexus()->drivers_constant()) {
flags[bit] = false;
break;
}
if (val != obj->pin_Data(bit,idx).nexus()->driven_value()) {
flags[bit] = false;
break;
}
}
if (! flags[bit]) {
/* This bit slice is too complex. Go on. */
continue;
}
reduce_width += 1;
}
/* If no slices can be reduced, then we are finished. */
if (reduce_width == 0) {
delete[]flags;
return;
}
/* Handle the very special case that all the slices can be
reduced. We don't need a MUX at all! */
if (reduce_width == width) {
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(obj->pin_Result(idx), obj->pin_Data(idx,0));
delete obj;
count += 1;
delete[]flags;
return;
}
/* Create a reduced mux with the same name and size, but fewer
slices. Connect all the slices that we are keeping. */
NetMux*tmp = new NetMux(scope, obj->name(),
width-reduce_width, size, obj->sel_width());
tmp->set_line(*obj);
for (unsigned idx = 0 ; idx < obj->sel_width() ; idx += 1)
connect(obj->pin_Sel(idx), tmp->pin_Sel(idx));
unsigned dst_bit = 0;
for (unsigned bit = 0 ; bit < width ; bit += 1) {
if (flags[bit]) {
connect(obj->pin_Result(bit), obj->pin_Data(bit,0));
continue;
}
connect(obj->pin_Result(bit), tmp->pin_Result(dst_bit));
for (unsigned idx = 0 ; idx < size ; idx += 1)
connect(obj->pin_Data(bit,idx), tmp->pin_Data(dst_bit,idx));
dst_bit += 1;
}
/* Add the new node. Delete the old node. Signal that we
change the design and may use a rescan. */
des->add_node(tmp);
delete obj;
delete[]flags;
count += 1;
}
void cprop_functor::lpm_ram_dq(Design*des, NetRamDq*obj)
{
if (lpm_ram_dq_const_address_(des,obj))
return;
}
/*
* Try to evaluate a constant address input. If we find it, then
* replace the NetRamDq with a direct link to the addressed word.
*/
bool cprop_functor::lpm_ram_dq_const_address_(Design*des, NetRamDq*obj)
{
NetMemory*mem = obj->mem();
NetNet* reg = mem->reg_from_explode();
/* I only know how to do this on exploded memories. */
if (reg == 0)
return false;
verinum sel (0UL, obj->awidth());
for (unsigned idx = 0 ; idx < obj->awidth() ; idx += 1) {
if (! obj->pin_Address(idx).nexus()->drivers_constant())
return false;
sel.set(idx, obj->pin_Address(idx).nexus()->driven_value());
}
unsigned long address = sel.as_ulong();
/* If the address is outside the ram, then leave this to the
code generator to figure out. */
if (address >= obj->size())
return false;
unsigned base = address * obj->width();
assert(base+obj->width() <= reg->pin_count());
for (unsigned idx = 0 ; idx < obj->width() ; idx += 1)
connect(reg->pin(base+idx), obj->pin_Q(idx));
if (debug_cprop) {
cerr << obj->get_line() << ": debug: Replace read port with"
<< " fixed link to word " << address << "." << endl;
}
delete obj;
count += 1;
return true;
}
/*
* This functor looks to see if the constant is connected to nothing
* but signals. If that is the case, delete the dangling constant and
@ -1038,6 +1316,18 @@ void cprop(Design*des)
/*
* $Log: cprop.cc,v $
* Revision 1.47.2.5 2006/04/23 04:26:13 steve
* Constant propagate addresses through NetRamDq read ports.
*
* Revision 1.47.2.4 2005/09/11 02:50:51 steve
* Fix overly agressive constant propagation through MUX causing lost Z bits.
*
* Revision 1.47.2.3 2005/08/28 22:00:39 steve
* Reduce mux slices that are constant throughout range.
*
* Revision 1.47.2.2 2005/08/28 19:51:02 steve
* More thorough constant propagation through MUX devices.
*
* Revision 1.47 2004/02/20 18:53:34 steve
* Addtrbute keys are perm_strings.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: design_dump.cc,v 1.149 2004/10/04 01:10:52 steve Exp $"
#ident "$Id: design_dump.cc,v 1.149.2.7 2006/08/23 04:09:14 steve Exp $"
#endif
# include "config.h"
@ -171,7 +171,8 @@ void NetObj::dump_node_pins(ostream&o, unsigned ind) const
if (pin(idx).is_linked()) {
const Nexus*nex = pin(idx).nexus();
o << nex << " " << nex->name();
const char*nex_name = nex->name();
o << nex << " " << (nex_name? nex_name : "????");
}
o << endl;
@ -216,6 +217,23 @@ void NetCompare::dump_node(ostream&o, unsigned ind) const
dump_obj_attr(o, ind+4);
}
void NetDecode::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_DECODE (NetDecode): " << name()
<< " ff=" << ff_->name() << ", word width=" << width() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetDemux::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_DEMUX (NetDemux): " << name()
<< " bus width=" << width() << ", address width=" << awidth()
<< ", word count=" << size() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
void NetDivide::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NET_DIVIDE (NetDivide): " << name() << endl;
@ -240,6 +258,7 @@ void NetMux::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "Multiplexer (NetMux): " << name()
<< " scope=" << scope()->name() << endl;
o << setw(ind+6) << "" << "source=" << get_line() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
@ -272,7 +291,12 @@ void NetFF::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_FF: " << name()
<< " scope=" << (scope()? scope()->name() : "")
<< " aset_value=" << aset_value_ << endl;
<< " aset_value=" << aset_value_
<< " sset_value=" << sset_value_;
if (demux_) o << " demux=" << demux_->name();
o << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
@ -355,8 +379,16 @@ void NetModulo::dump_node(ostream&o, unsigned ind) const
void NetRamDq::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_RAM_DQ (" << mem_->name() << "): "
<< name() << endl;
o << setw(ind) << "" << "LPM_RAM_DQ (";
if (mem_)
if (NetNet*tmp = mem_->reg_from_explode())
o << "exploded mem=" << tmp->name();
else
o << "mem=" << mem_->name();
o << "): " << name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
@ -537,6 +569,8 @@ void NetCase::dump(ostream&o, unsigned ind) const
break;
}
dump_proc_attr(o, ind+2);
for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) {
o << setw(ind+2) << "";
if (items_[idx].guard)
@ -842,6 +876,15 @@ void NetProc::dump(ostream&o, unsigned ind) const
o << setw(ind) << "" << "// " << typeid(*this).name() << endl;
}
void NetProc::dump_proc_attr(ostream&o, unsigned ind) const
{
unsigned idx;
for (idx = 0 ; idx < attr_cnt() ; idx += 1) {
o << setw(ind) << "" << "(* " << attr_key(idx) << " = "
<< attr_value(idx) << " *)" << endl;
}
}
/* Dump an expression that no one wrote a dump method for. */
void NetExpr::dump(ostream&o) const
{
@ -1089,6 +1132,27 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.149.2.7 2006/08/23 04:09:14 steve
* missing sig diagnostics.
*
* Revision 1.149.2.6 2006/07/10 00:21:50 steve
* Add support for full_case attribute.
*
* Revision 1.149.2.5 2006/04/16 19:26:37 steve
* Fix handling of exploded memories with partial or missing resets.
*
* Revision 1.149.2.4 2006/03/26 23:09:21 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.149.2.3 2006/03/12 07:34:16 steve
* Fix the memsynth1 case.
*
* Revision 1.149.2.2 2006/02/19 00:11:31 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.149.2.1 2006/01/18 01:23:23 steve
* Rework l-value handling to allow for more l-value type flexibility.
*
* Revision 1.149 2004/10/04 01:10:52 steve
* Clean up spurious trailing white space.
*

View File

@ -16,12 +16,12 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.7 2004/10/13 22:01:34 steve Exp $"
#ident "$Id: Makefile.in,v 1.7.2.1 2006/10/04 17:08:59 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.8
VERSION = 0.8.3
prefix = @prefix@
exec_prefix = @exec_prefix@

View File

@ -562,4 +562,5 @@ int main(int argc, char *argv[])
compile_and_link();
myExit(0);
return 0; // eliminate warnings.
}

View File

@ -16,7 +16,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.24 2004/10/13 22:01:34 steve Exp $"
#ident "$Id: Makefile.in,v 1.24.2.2 2006/05/08 04:33:35 steve Exp $"
#
#
SHELL = /bin/sh
@ -40,6 +40,8 @@ CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
MAN = @MAN@
PS2PDF = @PS2PDF@
CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@
CFLAGS = -Wall @CFLAGS@
@ -54,6 +56,7 @@ clean:
distclean: clean
rm -f Makefile
rm -rf autom4te.cache
O = main.o substit.o cflexor.o cfparse.o
@ -75,15 +78,23 @@ cflexor.o: cflexor.c cfparse.h cfparse_misc.h globals.h
cfparse.o: cfparse.c globals.h cfparse_misc.h
iverilog.ps: $(srcdir)/iverilog.man
man -t $(srcdir)/iverilog.man > iverilog.ps
$(MAN) -t $(srcdir)/iverilog.man > iverilog.ps
iverilog.pdf: iverilog.ps
ps2pdf iverilog.ps iverilog.pdf
$(PS2PDF) iverilog.ps iverilog.pdf
ifeq (@WIN32@,yes)
ifeq ($(MAN),none)
INSTALL_DOC = $(mandir)/man1/iverilog.1
else
ifeq ($(PS2PDF),none)
INSTALL_DOC = $(mandir)/man1/iverilog.1
else
INSTALL_DOC = $(prefix)/iverilog.pdf $(mandir)/man1/iverilog.1
INSTALL_DOCDIR = $(mandir)/man1
all: iverilog.pdf
endif
endif
INSTALL_DOCDIR = $(mandir)/man1
else
INSTALL_DOC = $(mandir)/man1/iverilog.1
INSTALL_DOCDIR = $(mandir)/man1

View File

@ -1,4 +1,4 @@
.TH iverilog 1 "$Date: 2004/10/04 01:10:56 $" Version "$Date: 2004/10/04 01:10:56 $"
.TH iverilog 1 "$Date: 2006/06/12 00:16:53 $" Version "$Date: 2006/06/12 00:16:53 $"
.SH NAME
iverilog - Icarus Verilog compiler
@ -212,6 +212,12 @@ inherit timescale from another file. Both probably mean that
timescales are inconsistent, and simulation timing can be confusing
and dependent on compilation order.
.TP 8
.B unused
This enables warnings for unused variables. This may detect variables
that are not assigned, or variables and nets that are not used, or
similar possible misuses of variables and nets.
.SH "SYSTEM FUNCTION TABLE FILES"
If the source file name as a \fB.sft\fP suffix, then it is taken to be
a system function table file. A System function table file is used to

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: main.c,v 1.65 2004/06/17 14:47:22 steve Exp $"
#ident "$Id: main.c,v 1.65.2.5 2006/07/07 21:31:50 steve Exp $"
#endif
# include "config.h"
@ -88,6 +88,10 @@ extern const char*optarg;
# define IVL_ROOT "."
#endif
#ifndef IVL_ROOT_VARIABLE
# define IVL_ROOT_VARIABLE "IVERILOG_ROOT"
#endif
# include "globals.h"
#include "cfparse_misc.h" /* cfparse() */
@ -291,7 +295,7 @@ static int t_default(char*cmd, unsigned ncmd)
static void process_warning_switch(const char*name)
{
if (strcmp(name,"all") == 0) {
strcat(warning_flags, "ipt");
strcat(warning_flags, "iptu");
} else if (strcmp(name,"implicit") == 0) {
if (! strchr(warning_flags+2, 'i'))
@ -302,6 +306,9 @@ static void process_warning_switch(const char*name)
} else if (strcmp(name,"timescale") == 0) {
if (! strchr(warning_flags+2, 't'))
strcat(warning_flags, "t");
} else if (strcmp(name,"unused") == 0) {
if (! strchr(warning_flags+2, 'u'))
strcat(warning_flags, "u");
} else if (strcmp(name,"no-implicit") == 0) {
char*cp = strchr(warning_flags+2, 'i');
if (cp) while (*cp) {
@ -320,6 +327,12 @@ static void process_warning_switch(const char*name)
cp[0] = cp[1];
cp += 1;
}
} else if (strcmp(name,"no-unused") == 0) {
char*cp = strchr(warning_flags+2, 'u');
if (cp) while (*cp) {
cp[0] = cp[1];
cp += 1;
}
}
}
@ -409,14 +422,13 @@ int process_generation(const char*name)
return 0;
}
int main(int argc, char **argv)
/*
* This function fills in th ivl_root directory with the appropriate
* path, based on operating system, build time configuration, and
* environment.
*/
static char* get_root_dir()
{
char*cmd;
unsigned ncmd;
int e_flag = 0;
int version_flag = 0;
int opt, idx, rc;
#ifdef __MINGW32__
{ char * s;
char basepath[1024];
@ -443,16 +455,56 @@ int main(int argc, char **argv)
s = strrchr(ivl_root, sep);
if (s) *s = 0;
strcat(ivl_root, "\\lib\\ivl");
base = ivl_root;
}
#else
/* In a UNIX environment, the IVL_ROOT from the Makefile is
dependable. It points to the $prefix/lib/ivl directory,
where the sub-parts are installed. */
strcpy(ivl_root, IVL_ROOT);
base = ivl_root;
{ char*var = 0;
/* In other systems, use the configured root. */
strcpy(ivl_root, IVL_ROOT);
/* In any case, the IVL_ROOT variable can be used to override
the install location at run time. If it is set, use that
value instead. */
if ( (var = getenv(IVL_ROOT_VARIABLE)) ) {
strncpy(ivl_root, var, MAXSIZE);
strcat(ivl_root, "/lib/ivl");
}
}
#endif
return ivl_root;
}
int main(int argc, char **argv)
{
char*cmd;
unsigned ncmd;
int e_flag = 0;
int version_flag = 0;
int opt, idx, rc;
base = get_root_dir();
#ifdef __MINGW32__
/* Under Windows, there is no point checking the root
directory. */
#else
/* On other systems, check that the root directory seems
reasonable. */
{ size_t tmp_len = strlen(base) + 16;
char* tmp = malloc(tmp_len);
snprintf(tmp, tmp_len, "%s%civl", base, sep);
if (0 != access(tmp, F_OK)) {
fprintf(stderr, "%s: INSTALLATION ERROR: Directory %s"
" does not contain ivl files.\n", argv[0], base);
fprintf(stderr, "%s: : Check installation"
" or set " IVL_ROOT_VARIABLE " correctly.\n", argv[0]);
return 1;
}
free(tmp);
}
#endif
/* Create a temporary file for communicating input parameters
@ -735,6 +787,21 @@ int main(int argc, char **argv)
/*
* $Log: main.c,v $
* Revision 1.65.2.5 2006/07/07 21:31:50 steve
* Root dir variable does not include lib/ivl components.
*
* Revision 1.65.2.4 2006/06/27 01:30:20 steve
* Fix unused var warning for mingw32 build.
*
* Revision 1.65.2.3 2006/06/14 03:01:49 steve
* Remove redundant call to get_root_dir.
*
* Revision 1.65.2.2 2006/06/12 00:16:53 steve
* Add support for -Wunused warnings.
*
* Revision 1.65.2.1 2006/03/26 21:47:26 steve
* More installation directory flexibility.
*
* Revision 1.65 2004/06/17 14:47:22 steve
* Add a .sft file for the system functions.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: dup_expr.cc,v 1.18 2004/06/17 16:06:18 steve Exp $"
#ident "$Id: dup_expr.cc,v 1.18.2.1 2006/06/12 00:16:50 steve Exp $"
#endif
# include "config.h"
@ -90,6 +90,7 @@ NetESignal* NetESignal::dup_expr() const
NetESignal*tmp = new NetESignal(net_, msi_, lsi_);
assert(tmp);
tmp->expr_width(expr_width());
tmp->set_line(*this);
return tmp;
}
@ -143,6 +144,9 @@ NetEVariable* NetEVariable::dup_expr() const
/*
* $Log: dup_expr.cc,v $
* Revision 1.18.2.1 2006/06/12 00:16:50 steve
* Add support for -Wunused warnings.
*
* Revision 1.18 2004/06/17 16:06:18 steve
* Help system function signedness survive elaboration.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elab_expr.cc,v 1.91 2004/10/04 01:10:52 steve Exp $"
#ident "$Id: elab_expr.cc,v 1.91.2.1 2006/06/12 00:16:50 steve Exp $"
#endif
# include "config.h"
@ -742,6 +742,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
}
NetESignal*node = new NetESignal(net);
node->set_line(*this);
assert(idx_ == 0);
// Non-constant bit select? punt and make a subsignal
@ -1005,6 +1006,9 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, bool) const
/*
* $Log: elab_expr.cc,v $
* Revision 1.91.2.1 2006/06/12 00:16:50 steve
* Add support for -Wunused warnings.
*
* Revision 1.91 2004/10/04 01:10:52 steve
* Clean up spurious trailing white space.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elab_net.cc,v 1.138 2004/10/04 03:09:38 steve Exp $"
#ident "$Id: elab_net.cc,v 1.138.2.3 2005/09/11 02:56:37 steve Exp $"
#endif
# include "config.h"
@ -1312,21 +1312,25 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
unsigned repeat = 1;
if (repeat_) {
verinum*rep = repeat_->eval_const(des, scope);
if (rep == 0) {
NetExpr*etmp = elab_and_eval(des, scope, repeat_);
assert(etmp);
NetEConst*erep = dynamic_cast<NetEConst*>(etmp);
if (erep == 0) {
cerr << get_line() << ": internal error: Unable to "
<< "evaluate constant repeat expression." << endl;
des->errors += 1;
return 0;
}
repeat = rep->as_ulong();
repeat = erep->value().as_ulong();
delete etmp;
if (repeat == 0) {
cerr << get_line() << ": error: Invalid repeat value."
cerr << get_line() << ": error: Concatenation repeat "
"may not be 0."
<< endl;
des->errors += 1;
delete rep;
return 0;
}
}
@ -1435,6 +1439,7 @@ NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope,
NetMux*mux = new NetMux(scope, scope->local_symbol(), 1,
sig_width, sel->pin_count());
mux->set_line(*this);
/* Connect the signal bits to the mux. Account for the
direction of the numbering (lsb to msb vs. msb to lsb) by
@ -2268,6 +2273,7 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
(true) connected to tru_sig. */
NetMux*mux = new NetMux(scope, scope->local_symbol(), dwidth, 2, 1);
mux->set_line(*this);
connect(mux->pin_Sel(0), expr_sig->pin(0));
/* Connect the data inputs. */
@ -2513,6 +2519,15 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
/*
* $Log: elab_net.cc,v $
* Revision 1.138.2.3 2005/09/11 02:56:37 steve
* Attach line numbers to NetMux devices.
*
* Revision 1.138.2.2 2005/02/19 16:39:30 steve
* Spellig fixes.
*
* Revision 1.138.2.1 2005/01/29 00:18:23 steve
* Fix evaluate of constants in netlist concatenation repeats.
*
* Revision 1.138 2004/10/04 03:09:38 steve
* Fix excessive error message.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elaborate.cc,v 1.308 2004/10/04 01:10:52 steve Exp $"
#ident "$Id: elaborate.cc,v 1.308.2.4 2006/07/10 00:21:50 steve Exp $"
#endif
# include "config.h"
@ -67,6 +67,21 @@ void PGate::elaborate(Design*des, NetScope*scope) const
typeid(*this).name() << endl;
}
void process_attributes(Design*des, NetScope*scope,
Attrib*dest, const map<perm_string,PExpr*>&table)
{
struct attrib_list_t*attrib_list = 0;
unsigned attrib_list_n = 0;
attrib_list = evaluate_attributes(table, attrib_list_n,
des, scope);
for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1)
dest->attribute(attrib_list[adx].key,
attrib_list[adx].val);
delete[]attrib_list;
}
/*
* Elaborate the continuous assign. (This is *not* the procedural
* assign.) Elaborate the lvalue and rvalue, and do the assignment.
@ -1179,6 +1194,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
tmp->set_line(*this);
NetESignal*sig = new NetESignal(tmp);
sig->set_line(*this);
/* Generate an assignment of the l-value to the temporary... */
string n = scope->local_hsymbol();
@ -1215,6 +1231,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
/* And build up the complex statement. */
NetBlock*bl = new NetBlock(NetBlock::SEQU, 0);
bl->set_line(*this);
bl->append(a1);
bl->append(st);
@ -1318,6 +1335,7 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
}
NetBlock*cur = new NetBlock(type, nscope);
cur->set_line(*this);
bool fail_flag = false;
if (nscope == 0)
@ -1388,6 +1406,7 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
NetCase*res = new NetCase(type_, expr, icount);
res->set_line(*this);
process_attributes(des, scope, res, attributes);
/* Iterate over all the case items (guard/statement pairs)
elaborating them. If the guard has no expression, then this
@ -1403,8 +1422,12 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
/* If there are no expressions, then this is the
default case. */
NetProc*st = 0;
if (cur->stat)
if (cur->stat) {
st = cur->stat->elaborate(des, scope);
} else {
st = new NetBlock(NetBlock::SEQU, scope);
st->set_line(*this);
}
res->set_case(inum, 0, st);
inum += 1;
@ -1413,16 +1436,19 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const
/* If there are one or more expressions, then
iterate over the guard expressions, elaborating
a separate case for each. (Yes, the statement
will be elaborated again for each.) */
a separate case for each. If the statement is
nul, then put an appropriate stub in place. */
NetExpr*gu = 0;
NetProc*st = 0;
assert(cur->expr[e]);
gu = elab_and_eval(des, scope, cur->expr[e]);
if (cur->stat)
if (cur->stat) {
st = cur->stat->elaborate(des, scope);
} else {
st = new NetBlock(NetBlock::SEQU, scope);
st->set_line(*this);
}
res->set_case(inum, gu, st);
inum += 1;
}
@ -1455,8 +1481,11 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
return if_->elaborate(des, scope);
else if (else_)
return else_->elaborate(des, scope);
else
return new NetBlock(NetBlock::SEQU, 0);
else {
NetBlock*tmp = new NetBlock(NetBlock::SEQU, 0);
tmp->set_line(*this);
return tmp;
}
}
// If the condition expression is more then 1 bits, then
@ -1625,6 +1654,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
}
NetBlock*block = new NetBlock(NetBlock::SEQU, 0);
block->set_line(*this);
/* Detect the case where the definition of the task is known
@ -1702,6 +1732,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
continue;
NetESignal*sig = new NetESignal(port);
sig->set_line(*this);
/* Generate the assignment statement. */
NetAssign*ass = new NetAssign(lv, sig);
@ -2481,6 +2512,7 @@ void PTask::elaborate(Design*des, NetScope*task) const
NetProc*st;
if (statement_ == 0) {
st = new NetBlock(NetBlock::SEQU, 0);
st->set_line(*this);
} else {
@ -2769,6 +2801,18 @@ Design* elaborate(list<perm_string>roots)
/*
* $Log: elaborate.cc,v $
* Revision 1.308.2.4 2006/07/10 00:21:50 steve
* Add support for full_case attribute.
*
* Revision 1.308.2.3 2006/06/12 00:16:51 steve
* Add support for -Wunused warnings.
*
* Revision 1.308.2.2 2005/12/10 03:30:50 steve
* Fix crash on block with assignments that assign lval to self.
*
* Revision 1.308.2.1 2005/11/13 22:28:14 steve
* Do not panic if case statement is nul.
*
* Revision 1.308 2004/10/04 01:10:52 steve
* Clean up spurious trailing white space.
*

18
emit.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: emit.cc,v 1.77 2004/10/04 01:10:53 steve Exp $"
#ident "$Id: emit.cc,v 1.77.2.2 2006/03/26 23:09:21 steve Exp $"
#endif
# include "config.h"
@ -86,6 +86,16 @@ bool NetConst::emit_node(struct target_t*tgt) const
return tgt->net_const(this);
}
bool NetDecode::emit_node(struct target_t*tgt) const
{
return tgt->lpm_decode(this);
}
bool NetDemux::emit_node(struct target_t*tgt) const
{
return tgt->lpm_demux(this);
}
bool NetDivide::emit_node(struct target_t*tgt) const
{
tgt->lpm_divide(this);
@ -511,6 +521,12 @@ bool emit(const Design*des, const char*type)
/*
* $Log: emit.cc,v $
* Revision 1.77.2.2 2006/03/26 23:09:21 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.77.2.1 2006/02/19 00:11:31 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.77 2004/10/04 01:10:53 steve
* Clean up spurious trailing white space.
*

37
eval.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval.cc,v 1.36 2003/06/21 01:21:43 steve Exp $"
#ident "$Id: eval.cc,v 1.36.2.3 2006/09/20 20:27:02 steve Exp $"
#endif
# include "config.h"
@ -112,7 +112,10 @@ verinum* PEBinary::eval_const(const Design*des, const NetScope*scope) const
case 'l': { // left shift (<<)
assert(r->is_defined());
unsigned long rv = r->as_ulong();
res = new verinum(verinum::V0, l->len());
unsigned use_wid = l->len();
if (! l->has_len())
use_wid += rv;
res = new verinum(verinum::V0, use_wid);
if (rv < res->len()) {
unsigned cnt = res->len() - rv;
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
@ -143,6 +146,27 @@ verinum* PEBinary::eval_const(const Design*des, const NetScope*scope) const
return res;
}
verinum* PEConcat::eval_const(const Design*des, const NetScope*scope) const
{
verinum*accum = parms_[0]->eval_const(des, scope);
if (accum == 0)
return 0;
for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
verinum*tmp = parms_[idx]->eval_const(des, scope);
/* Oops, found an argument that is not constant. Give up. */
if (tmp == 0) {
delete accum;
return 0;
}
assert(tmp);
*accum = concat(*accum, *tmp);
delete tmp;
}
return accum;
}
/*
* Evaluate an identifier as a constant expression. This is only
@ -240,6 +264,15 @@ verinum* PEUnary::eval_const(const Design*des, const NetScope*scope) const
/*
* $Log: eval.cc,v $
* Revision 1.36.2.3 2006/09/20 20:27:02 steve
* Fix left shift of small unsized constants.
*
* Revision 1.36.2.2 2005/12/18 21:06:01 steve
* Properly fail when concat is not actually constant.
*
* Revision 1.36.2.1 2005/12/07 03:28:44 steve
* Support constant concatenation of constants.
*
* Revision 1.36 2003/06/21 01:21:43 steve
* Harmless fixup of warnings.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval_tree.cc,v 1.62 2004/10/04 01:10:53 steve Exp $"
#ident "$Id: eval_tree.cc,v 1.62.2.3 2005/09/09 02:17:08 steve Exp $"
#endif
# include "config.h"
@ -215,6 +215,11 @@ NetEConst* NetEBComp::eval_eqeq_()
NetEConst* NetEBComp::eval_less_()
{
if (right_->expr_type() == ET_REAL)
return eval_leeq_real_(false, false);
if (left_->expr_type() == ET_REAL)
return eval_leeq_real_(false, false);
NetEConst*r = dynamic_cast<NetEConst*>(right_);
if (r == 0) return 0;
@ -224,6 +229,16 @@ NetEConst* NetEBComp::eval_less_()
return new NetEConst(result);
}
if (left_->expr_width() == 0) {
cerr << get_line() << ": internal error: "
<< "Having trouble evaluating left expression of < op."
<< endl;
cerr << get_line() << ": : "
<< "Expression is: "
<< *this << endl;
return 0;
}
/* Detect the case where the right side is greater that or
equal to the largest value the left side can possibly
have. */
@ -259,7 +274,7 @@ NetEConst* NetEBComp::eval_less_()
return new NetEConst(result);
}
NetEConst* NetEBComp::eval_leeq_real_()
NetEConst* NetEBComp::eval_leeq_real_(bool gt_flag, bool include_eq_flag)
{
NetEConst*vtmp;
NetECReal*rtmp;
@ -308,7 +323,16 @@ NetEConst* NetEBComp::eval_leeq_real_()
assert(0);
}
verinum result((lv <= rv)? verinum::V1 : verinum::V0, 1);
/* This function supports < and <=. If the eq_flag is true,
then include <=. Otherwise, include only <. */
bool flag;
if (gt_flag)
flag = include_eq_flag? (lv >= rv) : (lv > rv);
else
flag = include_eq_flag? (lv <= rv) : (lv < rv);
verinum result(flag? verinum::V1 : verinum::V0, 1);
vtmp = new NetEConst(result);
vtmp->set_line(*this);
@ -318,9 +342,9 @@ NetEConst* NetEBComp::eval_leeq_real_()
NetEConst* NetEBComp::eval_leeq_()
{
if (right_->expr_type() == ET_REAL)
return eval_leeq_real_();
return eval_leeq_real_(false, true);
if (left_->expr_type() == ET_REAL)
return eval_leeq_real_();
return eval_leeq_real_(false, true);
NetEConst*r = dynamic_cast<NetEConst*>(right_);
if (r == 0) return 0;
@ -374,23 +398,10 @@ NetEConst* NetEBComp::eval_leeq_()
NetEConst* NetEBComp::eval_gt_()
{
if ((left_->expr_type() == NetExpr::ET_REAL)
&& (right_->expr_type() == NetExpr::ET_REAL)) {
NetECReal*tmpl = dynamic_cast<NetECReal*>(left_);
if (tmpl == 0)
return 0;
NetECReal*tmpr = dynamic_cast<NetECReal*>(right_);
if (tmpr == 0)
return 0;
double ll = tmpl->value().as_double();
double rr = tmpr->value().as_double();
verinum result ((ll > rr)? verinum::V1 : verinum::V0, 1, true);
return new NetEConst(result);
}
if (right_->expr_type() == ET_REAL)
return eval_leeq_real_(true, false);
if (left_->expr_type() == ET_REAL)
return eval_leeq_real_(true, false);
NetEConst*l = dynamic_cast<NetEConst*>(left_);
if (l == 0) return 0;
@ -450,23 +461,10 @@ NetEConst* NetEBComp::eval_gt_()
NetEConst* NetEBComp::eval_gteq_()
{
if ((left_->expr_type() == NetExpr::ET_REAL)
&& (right_->expr_type() == NetExpr::ET_REAL)) {
NetECReal*tmpl = dynamic_cast<NetECReal*>(left_);
if (tmpl == 0)
return 0;
NetECReal*tmpr = dynamic_cast<NetECReal*>(right_);
if (tmpr == 0)
return 0;
double ll = tmpl->value().as_double();
double rr = tmpr->value().as_double();
verinum result ((ll >= rr)? verinum::V1 : verinum::V0, 1, true);
return new NetEConst(result);
}
if (right_->expr_type() == ET_REAL)
return eval_leeq_real_(true, true);
if (left_->expr_type() == ET_REAL)
return eval_leeq_real_(true, true);
NetEConst*l = dynamic_cast<NetEConst*>(left_);
if (l == 0) return 0;
@ -1551,6 +1549,15 @@ NetEConst* NetEUReduce::eval_tree()
/*
* $Log: eval_tree.cc,v $
* Revision 1.62.2.3 2005/09/09 02:17:08 steve
* Evaluate magnitude compare with real operands.
*
* Revision 1.62.2.2 2005/09/04 15:41:54 steve
* More explicit internal error message.
*
* Revision 1.62.2.1 2005/09/04 15:39:19 steve
* More explicit internal error message.
*
* Revision 1.62 2004/10/04 01:10:53 steve
* Clean up spurious trailing white space.
*

View File

@ -16,13 +16,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* $Id: sqrt-virtex.v,v 1.4 2003/11/25 18:35:31 steve Exp $"
* $Id: sqrt-virtex.v,v 1.4.2.2 2005/02/23 18:37:52 steve Exp $"
*/
/*
* This module is a synthesizeable square-root function. It is also a
* detailed example of how to target Xilinx Virtex parts using
* Icarus Verilog. In fact, for no particular reason other then to
* Icarus Verilog. In fact, for no particular reason other than to
* be excessively specific, I will step through the process of
* generating a design for a Spartan-II XC2S15-VQ100, and also how to
* generate a generic library part for larger Virtex designs.
@ -129,8 +129,8 @@
* This command creates from the chip.ngd the file "chip_root.v" that
* contains Verilog code that simulates the mapped design. This output
* Verilog has the single root module "chip_root", which came from the
* name of the root module when we were making hte EDIF file in the
* first place. The module has ports named just line the ports of the
* name of the root module when we were making the EDIF file in the
* first place. The module has ports named just like the ports of the
* chip_root module below.
*
* The generated Verilog uses the library in the directory

View File

@ -17,24 +17,64 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: expr_synth.cc,v 1.59 2004/06/30 02:16:26 steve Exp $"
#ident "$Id: expr_synth.cc,v 1.59.2.9 2006/08/08 02:17:48 steve Exp $"
#endif
# include "config.h"
# include <iostream>
# include <typeinfo>
# include "netlist.h"
# include "netmisc.h"
# include "compiler.h"
NetNet* NetExpr::synthesize(Design*des)
{
cerr << get_line() << ": internal error: cannot synthesize expression: "
<< *this << endl;
cerr << get_line() << ": : typeid="
<< typeid(*this).name() << endl;
des->errors += 1;
return 0;
}
/*
* For the NetEBitSel expression, create a NetMux node that selects a
* bit from the input.
*/
NetNet* NetEBitSel::synthesize(Design*des)
{
NetNet*net = sig_->synthesize(des);
assert(net);
NetNet*adr = idx_->synthesize(des);
if (adr == 0)
return 0;
NetScope*scope = adr->scope();
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, 1);
osig->set_line(*this);
osig->local_flag(true);
NetMux*mux = new NetMux(scope, scope->local_symbol(),
1, net->pin_count(), adr->pin_count());
des->add_node(mux);
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1)
connect(mux->pin_Data(0, idx), net->pin(idx));
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
connect(mux->pin_Sel(idx), adr->pin(idx));
connect(mux->pin_Result(0), osig->pin(0));
return osig;
}
/*
* Make an LPM_ADD_SUB device from addition operators.
*/
@ -408,7 +448,7 @@ NetNet* NetEBDiv::synthesize(Design*des)
default: {
cerr << get_line() << ": internal error: "
<< "NetEBDiv has unexpeced op() code: "
<< "NetEBDiv has unexpected op() code: "
<< op() << endl;
des->errors += 1;
@ -472,13 +512,18 @@ NetNet* NetEBLogic::synthesize(Design*des)
perm_string oname = scope->local_symbol();
olog = new NetLogic(scope, oname, 3, NetLogic::AND);
olog->set_line(*this);
connect(osig->pin(0), olog->pin(0));
des->add_node(olog);
/* XXXX Here, I need to reduce the parameters with
reduction or. */
/* Here, I need to reduce the parameters with
reduction or. Only do this if we must. */
if (lsig->pin_count() > 1)
lsig = reduction_or(des, lsig);
if (rsig->pin_count() > 1)
rsig = reduction_or(des, rsig);
/* By this point, the left and right parameters have been
reduced to single bit values. Now we just connect them to
@ -486,6 +531,11 @@ NetNet* NetEBLogic::synthesize(Design*des)
assert(lsig->pin_count() == 1);
connect(lsig->pin(0), olog->pin(1));
if (rsig->pin_count() != 1) {
cerr << olog->get_line() << ": internal error: "
<< "right argument not reduced. expr=" << *this << endl;
}
assert(rsig->pin_count() == 1);
connect(rsig->pin(0), olog->pin(2));
}
@ -566,7 +616,6 @@ NetNet* NetEBShift::synthesize(Design*des)
NetNet::IMPLICIT, expr_width());
osig->local_flag(true);
assert(op() == 'l');
NetCLShift*dev = new NetCLShift(scope, scope->local_symbol(),
osig->pin_count(),
rsig->pin_count(),
@ -640,6 +689,71 @@ NetNet* NetEConst::synthesize(Design*des)
return osig;
}
NetNet* NetEMemory::synthesize(Design*des)
{
NetScope*scope = mem_->scope();
NetNet*explode = mem_->explode_to_reg();
unsigned width = expr_width();
assert(idx_);
NetNet*addr = idx_->synthesize(des);
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT,
width);
osig->set_line(*this);
if (explode) {
if (debug_synth)
cerr << get_line() << ": debug: synthesize read of "
<< explode->pin_count() << " bit exploded memory." << endl;
/* Only make a muc big enough to address the words that
the address can generate. (If the address is
0-extended, then only the low words are addressable.) */
unsigned use_count = mem_->count();
if (use_count > (1U << addr->pin_count())) {
use_count = 1 << addr->pin_count();
if (debug_synth)
cerr << get_line() << ": debug: "
<< "Index expression can only address "
<< use_count << " of "
<< mem_->count() << " words." << endl;
}
/* This is a reference to an exploded memory. So locate
the reg vector and use the addr expression as a
select into a MUX. */
NetMux*mux = new NetMux(scope, scope->local_symbol(),
width, use_count, addr->pin_count());
des->add_node(mux);
mux->set_line(*this);
for (unsigned idx = 0 ; idx < width ; idx += 1)
connect(mux->pin_Result(idx), osig->pin(idx));
for (unsigned idx = 0 ; idx < mux->sel_width() ; idx += 1)
connect(mux->pin_Sel(idx), addr->pin(idx));
for (unsigned wrd = 0 ; wrd < use_count ; wrd += 1)
for (unsigned idx = 0 ; idx < width ; idx += 1) {
unsigned bit = wrd*width + idx;
connect(mux->pin_Data(idx, wrd), explode->pin(bit));
}
if (debug_synth)
cerr << get_line() << ": debug: synthesis done." << endl;
} else {
cerr << get_line() << ": internal error: Synthesize memory "
<< "expression that is not exploded?" << endl;
des->errors += 1;
}
return osig;
}
NetNet* NetECReal::synthesize(Design*des)
{
cerr << get_line() << ": error: Real constants are "
@ -811,6 +925,7 @@ NetNet* NetETernary::synthesize(Design *des)
perm_string oname = csig->scope()->local_symbol();
NetMux *mux = new NetMux(csig->scope(), oname, width, 2, 1);
mux->set_line(*this);
for (unsigned idx = 0 ; idx < width; idx += 1) {
connect(tsig->pin(idx), mux->pin_Data(idx, 1));
connect(fsig->pin(idx), mux->pin_Data(idx, 0));
@ -854,6 +969,21 @@ NetNet* NetETernary::synthesize(Design *des)
*/
NetNet* NetESignal::synthesize(Design*des)
{
if (warn_unused) {
if (net_->peek_lref() == 0 && net_->type()==NetNet::REG) {
cerr << get_line() << ": warning: "
<< "reg " << net_->name()
<< " is used by logic but never assigned." << endl;
}
if (net_->peek_lref() == 0 && net_->type()==NetNet::INTEGER) {
cerr << get_line() << ": warning: "
<< "reg " << net_->name()
<< " is used by logic but never assigned." << endl;
}
}
/* If there is no part select, then the synthesis is trivial. */
if ((lsi_ == 0) && (msi_ == (net_->pin_count() - 1)))
return net_;
@ -866,6 +996,7 @@ NetNet* NetESignal::synthesize(Design*des)
perm_string name = scope->local_symbol();
NetNet*tmp = new NetNet(scope, name, NetNet::WIRE, wid);
tmp->local_flag(true);
tmp->set_line(*this);
for (unsigned idx = 0 ; idx < wid ; idx += 1)
connect(tmp->pin(idx), net_->pin(idx+lsi_));
@ -875,6 +1006,33 @@ NetNet* NetESignal::synthesize(Design*des)
/*
* $Log: expr_synth.cc,v $
* Revision 1.59.2.9 2006/08/08 02:17:48 steve
* Improved nexus management performance.
*
* Revision 1.59.2.8 2006/06/15 01:57:26 steve
* Handle simple memory addressing in expression synthesis.
*
* Revision 1.59.2.7 2006/06/14 03:02:54 steve
* synthesis for NetEBitSel.
*
* Revision 1.59.2.6 2006/06/12 00:16:52 steve
* Add support for -Wunused warnings.
*
* Revision 1.59.2.5 2006/05/15 03:55:22 steve
* Fix synthesis of expressions with land of vectors.
*
* Revision 1.59.2.4 2006/04/10 03:43:39 steve
* Exploded memories accessed by constant indices.
*
* Revision 1.59.2.3 2006/03/16 05:39:20 steve
* Right shifts really are allowed.
*
* Revision 1.59.2.2 2005/09/11 02:56:37 steve
* Attach line numbers to NetMux devices.
*
* Revision 1.59.2.1 2005/02/19 16:39:31 steve
* Spellig fixes.
*
* Revision 1.59 2004/06/30 02:16:26 steve
* Implement signed divide and signed right shift in nets.
*
@ -883,82 +1041,5 @@ NetNet* NetESignal::synthesize(Design*des)
*
* Revision 1.57 2004/06/12 15:00:02 steve
* Support / and % in synthesized contexts.
*
* Revision 1.56 2004/06/01 01:04:57 steve
* Fix synthesis method for logical and/or
*
* Revision 1.55 2004/02/20 18:53:35 steve
* Addtrbute keys are perm_strings.
*
* Revision 1.54 2004/02/18 17:11:56 steve
* Use perm_strings for named langiage items.
*
* Revision 1.53 2004/02/15 04:23:48 steve
* Fix evaluation of compare to constant expression.
*
* Revision 1.52 2003/11/10 19:39:20 steve
* Remove redundant scope tokens.
*
* Revision 1.51 2003/10/27 06:04:21 steve
* More flexible width handling for synthesized add.
*
* Revision 1.50 2003/09/26 02:44:27 steve
* Assure ternary arguments are wide enough.
*
* Revision 1.49 2003/09/03 23:31:36 steve
* Support synthesis of constant downshifts.
*
* Revision 1.48 2003/08/28 04:11:18 steve
* Spelling patch.
*
* Revision 1.47 2003/08/09 03:23:40 steve
* Add support for IVL_LPM_MULT device.
*
* Revision 1.46 2003/07/26 03:34:42 steve
* Start handling pad of expressions in code generators.
*
* Revision 1.45 2003/06/24 01:38:02 steve
* Various warnings fixed.
*
* Revision 1.44 2003/04/19 04:52:56 steve
* Less picky about expression widths while synthesizing ternary.
*
* Revision 1.43 2003/04/08 05:07:15 steve
* Detect constant shift distances in synthesis.
*
* Revision 1.42 2003/04/08 04:33:55 steve
* Synthesize shift expressions.
*
* Revision 1.41 2003/03/06 00:28:41 steve
* All NetObj objects have lex_string base names.
*
* Revision 1.40 2003/02/26 01:29:24 steve
* LPM objects store only their base names.
*
* Revision 1.39 2003/01/30 16:23:07 steve
* Spelling fixes.
*
* Revision 1.38 2003/01/26 21:15:58 steve
* Rework expression parsing and elaboration to
* accommodate real/realtime values and expressions.
*
* Revision 1.37 2002/11/17 23:37:55 steve
* Magnitude compare to 0.
*
* Revision 1.36 2002/08/12 01:34:59 steve
* conditional ident string using autoconfig.
*
* Revision 1.35 2002/07/07 22:31:39 steve
* Smart synthesis of binary AND expressions.
*
* Revision 1.34 2002/07/05 21:26:17 steve
* Avoid emitting to vvp local net symbols.
*
* Revision 1.33 2002/05/26 01:39:02 steve
* Carry Verilog 2001 attributes with processes,
* all the way through to the ivl_target API.
*
* Divide signal reference counts between rval
* and lval references.
*/

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: functor.cc,v 1.32 2004/10/04 01:10:53 steve Exp $"
#ident "$Id: functor.cc,v 1.32.2.1 2006/04/23 04:26:14 steve Exp $"
#endif
# include "config.h"
@ -79,6 +79,9 @@ void functor_t::lpm_mux(class Design*, class NetMux*)
{
}
void functor_t::lpm_ram_dq(class Design*, class NetRamDq*)
{
}
void NetScope::run_functor(Design*des, functor_t*fun)
{
@ -206,6 +209,11 @@ void NetMux::functor_node(Design*des, functor_t*fun)
fun->lpm_mux(des, this);
}
void NetRamDq::functor_node(Design*des, functor_t*fun)
{
fun->lpm_ram_dq(des, this);
}
proc_match_t::~proc_match_t()
{
}
@ -267,6 +275,9 @@ int proc_match_t::event_wait(NetEvWait*)
/*
* $Log: functor.cc,v $
* Revision 1.32.2.1 2006/04/23 04:26:14 steve
* Constant propagate addresses through NetRamDq read ports.
*
* Revision 1.32 2004/10/04 01:10:53 steve
* Clean up spurious trailing white space.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: functor.h,v 1.20 2002/08/12 01:34:59 steve Exp $"
#ident "$Id: functor.h,v 1.20.2.1 2006/04/23 04:26:14 steve Exp $"
#endif
/*
@ -77,6 +77,9 @@ struct functor_t {
/* This method is called for each MUX. */
virtual void lpm_mux(class Design*des, class NetMux*);
/* This is called for eacm RamDq device. */
virtual void lpm_ram_dq(class Design*des, class NetRamDq*);
};
struct proc_match_t {
@ -92,6 +95,9 @@ struct proc_match_t {
/*
* $Log: functor.h,v $
* Revision 1.20.2.1 2006/04/23 04:26:14 steve
* Constant propagate addresses through NetRamDq read ports.
*
* Revision 1.20 2002/08/12 01:34:59 steve
* conditional ident string using autoconfig.
*

View File

@ -62,12 +62,15 @@ ivl_logic_udp
ivl_lpm_aset_value
ivl_lpm_async_clr
ivl_lpm_async_set
ivl_lpm_attr_cnt
ivl_lpm_attr_val
ivl_lpm_basename
ivl_lpm_clk
ivl_lpm_data
ivl_lpm_datab
ivl_lpm_data2
ivl_lpm_data2_width
ivl_lpm_decode
ivl_lpm_define
ivl_lpm_enable
ivl_lpm_memory

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: ivl_target.h,v 1.126 2004/10/04 01:10:53 steve Exp $"
#ident "$Id: ivl_target.h,v 1.126.2.5 2006/04/16 19:26:37 steve Exp $"
#endif
#ifdef __cplusplus
@ -226,6 +226,8 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_CMP_GE = 1,
IVL_LPM_CMP_GT = 2,
IVL_LPM_CMP_NE = 11,
IVL_LPM_DECODE = 15,
IVL_LPM_DEMUX = 16,
IVL_LPM_DIVIDE = 12,
IVL_LPM_FF = 3,
IVL_LPM_MOD = 13,
@ -629,6 +631,11 @@ extern const char* ivl_udp_name(ivl_udp_t net);
* the LPM type, but it generally has to do with the width of the
* output data path.
*
* ivl_lpm_attr_cnt
* ivl_lpm_attr_val
* These functions access attributes attached to LPM devices. These
* attributes may be explicit attributes collected from the Verilog
* source, or implicit attributes generated by the compiler.
*
* These functions apply to a subset of the LPM devices, or may have
* varying meaning depending on the device:
@ -642,13 +649,18 @@ extern const char* ivl_udp_name(ivl_udp_t net);
* Return the input data nexus for device types that have a second
* input vector. For example, arithmetic devices are like this.
*
* ivl_lpm_decode
* Return the DECODER associated with this LPM_FF device. The
* decoder for a FF takes an input address and generates an enable
* input for no more then 1 bit (can be none) of the FF device.
*
* ivl_lpm_q
* Return the output data nexus for device types that have a single
* output vector. This is most devices, it turns out.
*
* ivl_lpm_selects
* This is the size of the select input for a LPM_MUX device, or the
* address bus width of an LPM_RAM.
* This is the size of the select input for a LPM_MUX or LPM_DECODE
* device, or the address bus width of an LPM_RAM.
*
* ivl_lpm_signed
* Arithmetic LPM devices may be signed or unsigned if there is a
@ -658,6 +670,64 @@ extern const char* ivl_udp_name(ivl_udp_t net);
* In addition to a width, some devices have a size. The size is
* often the number of inputs per out, i.e., the number of inputs
* per bit for a MUX.
*
* SEMANTIC NOTES:
*
* - IVL_LPM_FF
* The IVL_LPM_FF and IVL_LPM_DECODE devices are closely related. If
* the ivl_lpm_decode function returns a non-nil value, then the
* decoder represents an extra ENABLE-like input, where exactly <N>
* bits of the width of the FF is enabled. The ivl_lpm_width of the
* decoder defines <N>.
*
* The decoder inputs are the address that selects the FF to be
* enabled, and the ivl_lpm_selects for the decoder gives the width of
* the address. The address of the LSB of the memory, then, is the
* word width times the input address. For a simple l-value bit
* select, the word width <N> will be 1, and the address goes directly
* to the bit. Otherwise, <N>*address gets to the first bit of the word.
*
* The core compiler generates these attributes in certain cases:
*
* - ivl:clock_polarity
* If present, the string value can be "INVERT". That indicates
* that the clock is negedge sensitive instead of the default
* posedge sensitive.
*
* - IVL_LPM_RAM
* The IVL_LPM_RAM may also appear as a READ port for a FF array. In
* this case, the IVL_LPM_RAM device has an ivl_lpm_width that is the
* width of the word, and an ivl_lpm_size that is the number of words
* in the array. In effect, the IVL_LPM_RAM reorganizes a vector into
* an array of words. If this is happening, then the ivl_lpm_memory
* will return 0.
*
* The ivl_lpm_q function gets the output nexa of the read port. The
* "q" port has as many bits as the width. The ivl_lpm_data2 function
* gets the nexa of the input, with the sdx the word address and the
* idx the bit within the word.
*
* - IVL_LPM_DEMUX
* This device is a form of bit replacement. The device has a data bus
* width (ivl_lpm_width) and an address width. The Data outputs are
* ivl_lpm_q and have the data bus width. The ivl_lpm_data functions are
* inputs to the device. Normally, the device passes the data inputs
* through to the Q output.
*
* The IVL_LPM_DEMUX also has a size (ivl_lpm_size) which is the
* number of addressable units in the device. If the device is bit-
* addressable, then the size is the same as the width. I.e. if
* ivl_lpm_width == ivl_lpm_size, then the address selects a single
* bit. If ivl_lpm_width/ivl_lpm_size == 8, then the address selects
* words of 8 bits and there are ivl_lpm_size of them. The
* ivl_lpm_width will always be an exact multiple of
* ivl_lpm_size. This is slightly different from the meaning of width
* in memory ports, but reflects that the DEMUX manipulates fixed
* width ranges within a single vector.
*
* The ivl_lpm_select inputs address a bit of the device. The
* addressed bit is substituted by the replacement bit. This
* replacement bit comes from the ivl_lpm_datab(net,0) nexus.
*/
extern const char* ivl_lpm_name(ivl_lpm_t net); /* (Obsolete) */
@ -667,6 +737,9 @@ extern int ivl_lpm_signed(ivl_lpm_t net);
extern ivl_lpm_type_t ivl_lpm_type(ivl_lpm_t net);
extern unsigned ivl_lpm_width(ivl_lpm_t net);
extern unsigned ivl_lpm_attr_cnt(ivl_lpm_t net);
extern ivl_attribute_t ivl_lpm_attr_val(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_FF */
extern ivl_nexus_t ivl_lpm_async_clr(ivl_lpm_t net);
extern ivl_nexus_t ivl_lpm_async_set(ivl_lpm_t net);
@ -676,26 +749,29 @@ extern ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net);
extern ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net);
/* IVL_LPM_FF IVL_LPM_RAM */
extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net);
/* IVL_LPM_FF */
extern ivl_lpm_t ivl_lpm_decode(ivl_lpm_t net);
/* IVL_LPM_UFUNC */
extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net);
/* IVL_LPM_FF IVL_LPM_RAM */
extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net);
/* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_RAM IVL_LPM_SUB */
/* IVL_LPM_ADD IVL_LPM_DEMUX IVL_LPM_FF IVL_LPM_MULT */
/* IVL_LPM_RAM IVL_LPM_SUB */
extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_SUB */
/* IVL_LPM_ADD IVL_LPM_DEMUX IVL_LPM_MULT IVL_LPM_SUB */
/* IVL_LPM_MUX IVL_LPM_UFUNC */
extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx);
extern ivl_nexus_t ivl_lpm_data2(ivl_lpm_t net, unsigned sdx, unsigned idx);
/* IVL_LPM_UFUNC */
extern unsigned ivl_lpm_data2_width(ivl_lpm_t net, unsigned sdx);
/* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_RAM IVL_LPM_SUB
/* IVL_LPM_ADD IVL_LPM_DEMUX IVL_LPM_FF IVL_LPM_MULT IVL_LPM_RAM IVL_LPM_SUB
IVL_LPM_UFUNC */
extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_MUX IVL_LPM_RAM */
/* IVL_LPM_MUX IVL_LPM_DECODE IVL_LPM_DEMUX IVL_LPM_RAM */
extern unsigned ivl_lpm_selects(ivl_lpm_t net);
/* IVL_LPM_MUX IVL_LPM_RAM */
/* IVL_LPM_MUX IVL_LPM_DECODE IVL_LPM_DEMUX IVL_LPM_RAM */
extern ivl_nexus_t ivl_lpm_select(ivl_lpm_t net, unsigned idx);
/* IVL_LPM_MUX */
/* IVL_LPM_DEMUX, IVL_LPM_MUX, IVL_LPM_RAM */
extern unsigned ivl_lpm_size(ivl_lpm_t net);
/* IVL_LPM_RAM */
extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net);
@ -1236,6 +1312,21 @@ _END_DECL
/*
* $Log: ivl_target.h,v $
* Revision 1.126.2.5 2006/04/16 19:26:37 steve
* Fix handling of exploded memories with partial or missing resets.
*
* Revision 1.126.2.4 2006/03/26 23:09:22 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.126.2.3 2006/03/12 07:34:16 steve
* Fix the memsynth1 case.
*
* Revision 1.126.2.2 2006/02/25 05:03:28 steve
* Add support for negedge FFs by using attributes.
*
* Revision 1.126.2.1 2006/02/19 00:11:31 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.126 2004/10/04 01:10:53 steve
* Clean up spurious trailing white space.
*

View File

@ -37,7 +37,7 @@ valid options include:
Predefine the symbol ``name'' to have the specified
value. If the value is not specified, then ``1'' is
used. This is mostly of use for controlling conditional
compilaiton.
compilation.
This option does *not* override existing `define
directives in the source file.

View File

@ -17,7 +17,7 @@ const char COPYRIGHT[] =
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: main.c,v 1.20 2004/09/10 00:15:45 steve Exp $"
#ident "$Id: main.c,v 1.20.2.1 2006/06/27 01:37:14 steve Exp $"
#endif
# include "config.h"
@ -126,8 +126,8 @@ int main(int argc, char*argv[])
int opt, idx;
const char*flist_path = 0;
unsigned flag_errors = 0;
char*out_path = 0;
char *dep_path = NULL;
const char*out_path = 0;
const char*dep_path = NULL;
FILE*out;
/* Define preprocessor keywords that I plan to just pass. */
@ -290,6 +290,9 @@ int main(int argc, char*argv[])
/*
* $Log: main.c,v $
* Revision 1.20.2.1 2006/06/27 01:37:14 steve
* Fix const/non-const warnings.
*
* Revision 1.20 2004/09/10 00:15:45 steve
* Remove bad casts.
*

View File

@ -1,4 +1,6 @@
%option never-interactive
%{
/*
* Copyright (c) 1998-2000 Stephen Williams (steve@icarus.com)
@ -19,7 +21,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: lexor.lex,v 1.86 2004/06/13 04:56:54 steve Exp $"
#ident "$Id: lexor.lex,v 1.86.2.3 2006/05/08 04:33:35 steve Exp $"
#endif
# include "config.h"
@ -179,6 +181,8 @@ W [ \t\b\f\r]+
<UDPTABLE>\(01\) { return 'r'; }
<UDPTABLE>\(0[xX]\) { return 'Q'; }
<UDPTABLE>\(b[xX]\) { return 'q'; }
<UDPTABLE>\(b0\) { return 'f'; /* b0 is 10|00, but only 10 is meaningful */}
<UDPTABLE>\(b1\) { return 'r'; /* b1 is 11|01, but only 01 is meaningful */}
<UDPTABLE>\(0\?\) { return 'P'; }
<UDPTABLE>\(10\) { return 'f'; }
<UDPTABLE>\(1[xX]\) { return 'M'; }

View File

@ -16,7 +16,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.34 2004/10/04 01:10:07 steve Exp $"
#ident "$Id: Makefile.in,v 1.34.2.1 2005/02/23 18:40:24 steve Exp $"
#
#
SHELL = /bin/sh
@ -93,6 +93,7 @@ clean:
distclean: clean
rm -f Makefile config.status config.log config.cache
rm -rf autom4te.cache
install:: all installdirs $(libdir64)/libveriuser.a $(INSTALL32)

View File

@ -1,6 +1,8 @@
AC_INIT(Makefile.in)
AC_CONFIG_HEADER(config.h)
AC_CANONICAL_HOST
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_RANLIB

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: load_module.cc,v 1.12 2003/06/05 04:31:09 steve Exp $"
#ident "$Id: load_module.cc,v 1.12.2.1 2005/03/22 15:53:12 steve Exp $"
#endif
# include "config.h"
@ -88,7 +88,7 @@ bool load_module(const char*type)
cerr << "Executing: " << cmdline << endl;
pform_parse(path, file);
fclose(file);
pclose(file);
free(cmdline);
} else {
@ -193,6 +193,9 @@ int build_library_index(const char*path, bool key_case_sensitive)
/*
* $Log: load_module.cc,v $
* Revision 1.12.2.1 2005/03/22 15:53:12 steve
* popen must be matched by pclose.
*
* Revision 1.12 2003/06/05 04:31:09 steve
* INclude missing assert.h in load_module.
*

24
main.cc
View File

@ -19,7 +19,7 @@ const char COPYRIGHT[] =
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: main.cc,v 1.86 2004/10/04 01:10:53 steve Exp $"
#ident "$Id: main.cc,v 1.86.2.3 2006/06/12 00:16:53 steve Exp $"
#endif
# include "config.h"
@ -103,6 +103,7 @@ FILE *depend_file = NULL;
bool warn_implicit = false;
bool warn_timescale = false;
bool warn_portbinding = false;
bool warn_unused = false;
bool error_implicit = false;
@ -112,6 +113,9 @@ bool error_implicit = false;
bool debug_scopes = false;
bool debug_eval_tree = false;
bool debug_elaborate = false;
bool debug_synth = false;
bool debug_cprop = false;
/*
* Verbose messages enabled.
*/
@ -314,6 +318,12 @@ static void read_iconfig_file(const char*ipath)
} else if (strcmp(cp,"elaborate") == 0) {
debug_elaborate = true;
cerr << "debug: Enable elaborate debug" << endl;
} else if (strcmp(cp,"synth") == 0) {
debug_synth = true;
cerr << "debug: Enable synthesis debug" << endl;
} else if (strcmp(cp,"cprop") == 0) {
debug_cprop = true;
cerr << "debug: Enable cprop debug" << endl;
} else {
}
@ -376,6 +386,9 @@ static void read_iconfig_file(const char*ipath)
case 't':
warn_timescale = true;
break;
case 'u':
warn_unused = true;
break;
default:
break;
}
@ -744,6 +757,15 @@ int main(int argc, char*argv[])
/*
* $Log: main.cc,v $
* Revision 1.86.2.3 2006/06/12 00:16:53 steve
* Add support for -Wunused warnings.
*
* Revision 1.86.2.2 2006/04/23 04:25:45 steve
* Add cprop debugging.
*
* Revision 1.86.2.1 2006/04/01 01:37:24 steve
* Add synth debug flag
*
* Revision 1.86 2004/10/04 01:10:53 steve
* Clean up spurious trailing white space.
*

217
mingw.txt
View File

@ -2,7 +2,7 @@
MINGW PORT OF ICARUS VERILOG
Copyright 2003 Stephen Williams <steve@icarus.com>
Copyright 2006 Stephen Williams <steve@icarus.com>
Icarus Verilog source can be compiled with the mingw C/C++ compilers
@ -12,13 +12,13 @@ or without Cygwin, so this is the preferred Windows distribution form.
The configure scripts automatically detect that the compilers in use
are the mingw compilers and will configure the Makefiles appropriately.
However, the mingw tools do not include all the other tools around the
compiler, including the shell interpreter for the configure script,
bison, flex, gperf, etc. Therefore, you still need Cygwin to compile
Icarus Verilog, even if you don't need the Cygwin compilers. There are
also a few precompiled library prerequisites that you need.
The mingw patch doesn't contain tools beyond the compiler, but there
is the "msys" package that the makers of Mingw publish that has enough
extra tools to get most everything else working. There are a few extra
packages needed beyond mingw and msys, and the following instructions
explain how to get them and install them.
* Some Preliminary Comments
* Some Preliminary Comments -- PLEASE READ ME --
The Windows port of Icarus Verilog is the most difficult of all the
ports. The Windows system off the shelf is completely stripped, devoid
@ -26,7 +26,15 @@ of any support for software development. Everything needed to compile
Icarus Verilog must be collected from various sources and stitched
together by hand. Normal human beings with a basic understanding of
software development can do this, but some patience (and access to the
Internet) is required. You may choose to print these instructions.
Internet) is required. You may choose to print these instructions. FOR
BEST RESULTS, FOLLOW THESE INSTRUCTIONS CAREFULLY.
NOTE that if you have Cygwin installed, it is best to not use a cygwin
window to do the build, as the Cygwin tools will intermix with the
mingw tools such that it is hard to be sure you are using the right
compiler. Thus, it is recommended that these steps be *not* done in a
Cygwin window. Use an MSYS window instead, and be careful that your
msys/mingw tools are not masked by paths that point to Cygwin binaries.
I have no plans to intentionally support MSVC++ compilation. Don't ask.
@ -36,13 +44,15 @@ This is a brief list of prerequisite packages, along with the URL
where each can be found. In most cases, the specific version is not
critical, but these are the versions I use.
Cygwin <http://cygwin.com>
Mingw32-2.0.0 <http://www.mingw.org>
msys-1.0 <http://www.mingw/org>
msysDTK-1.0 <http://www.mingw.org>
Mingw32-5.x <http://www.mingw.org>
readline-4.2-20010727.zip <http://mingwrep.sourceforge.net>
bzip2-1.0.2-bin.zip <http://gnuwin32.sourceforge.net>
zlib-1.1.4-bin.zip <http://gnuwin32.sourceforge.net>
bzip2-1.0.2-lib.zip <http://gnuwin32.sourceforge.net>
zlib-1.1.4-lib.zip <http://gnuwin32.sourceforge.net>
bzip2-1.0.3 <http://gnuwin32.sourceforge.net>
zlib-1.2.3 <http://gnuwin32.sourceforge.net>
gperf-3.0.1 <http://gnuwin32.sourceforge.net>
bison-2.1 <http://gnuwin32.sourceforge.net>
flex-2.5.4a <http://gnuwin32.sourceforge.net>
The above table lists the packages required. It is convenient to
install them in the above order. Many of these packages are also
@ -55,59 +65,38 @@ installation of Icarus Verilog is complete. These are only needed to
build the compiler. The Mingw32 package can be used to compile VPI
modules if you choose.
* Install Cygwin
* Install MSYS and msysDTK
So, step 1 is "Download and Install Cygwin." See the web page
http://www.cygwin.com for instructions and the files to do
this. Cygwin *is* a kool package, and is worth having anyhow. There is
a convenient setup program that you download first. You execute the
setup program, and that prompts you to select the package you want.
The msys package is available from the mingw download site. This is
not the compiler but a collection of *nix tools ported to Windows and
wrapped in a convenient installer. The msys package is all the various
basic tools (shells, file utils, etc) and the msysDTK is extra
developer tools other then the compiler.
You need in particular the Cygwin base, bison (see notes) flex, make
and gperf. If you are compiling from CVS, you also need cvs, rcs and
automake packages. You will also need tar and gunzip, but these are
hard to not install. I recommend installing the "which" package as
well. Beyond the basics, be sure to install these Cygwin packages:
Download the msys-1.x.x.exe and msysdtc-1.x.x.exe binaries. These are
self-installing packages. Install msys first, and then msysDTC. Most
likely, you want to install them in c:/msys. (The msysDTK is installed
in the same location, as it is an add-on.)
bison (*not* 1.875. See Notes.)
flex
ghostscript (makes the documentation)
gperf
gzip
make
strip
tar (tar and gunzip for unpacking the source)
unzip (For unpacking zip compressed packages.)
which
This install should be easy and reliable.
NOTES:
bison-1.875 is broken, it generates invalid C/C++ code. You
don't want that version for anything you do. If you have that
version (use "bison -V" to check the version) then use the
Cygwin setup program to get a different version. I've downgraded
to 1.75 and couldn't be happier. In fact, a whole host of insane
bison bugs can be avoided that way.
There is a mingw32 runtime package included in the Cygwin
distribution. You do *not* need that, as you will be getting
everything from the mingw32 distribution itself.
Other then the install of mingw32, most of the remaining steps are
best done in a Cygwin window. When you installed Cygwin, a start menu
entry was created to allow you to start up the Cygwin window. I'll use
the string "$ " to represent a command prompt in this window, because
that is the usual bash prompt.
The installation will leave an "msys" icon on your desktop and in the
mingw sub-menu of your Start menu. This icon brings up a shell window
(a command line) that has paths all set up for executing msys and
mingw commands. This is what you will want to use while executing
commands below.
* Install Mingw32
The obvious step 2, then, is install the mingw compilers. These can be
found at the web page <http://www.mingw.org>. The Mingw-2.x.x version
comes prepackaged in a convenient, Windows style, installer. I
recommend you download this package instead of picking and choosing
bits.
found at the web page <http://www.mingw.org>. The Mingw-5.x.x package
is a convenient remote installer. Download this program and run
it. The installer will ask wich components you want to install. You
need only the base C compiler and the C++ compiler. (You may install
other languages if you wish.)
When I install Mingw32 (using the installer) I typically set a
destination directory of d:\mingw-2.0.0 or the like. You will be using
destination directory of d:\mingw or the like. You will be using
that path later.
NOTES:
@ -115,6 +104,10 @@ that path later.
need Mingw32, even if you are using a precompiled binary. VPI
modules only require Mingw32, and none of the other libraries.
Finally, as part of installing the mingw32 compilers, remember to add
the mingw/bin directory to your path. You will need that to be able to
find the compilers later.
* Install Mingw32 Packages
There is a collection of precompiled libraries and add-on packages
@ -123,86 +116,94 @@ with simplified Windows installers, but they are pretty easy to
install by hand. Icarus Verilog uses the readline-4.2 package from
that collection.
Since I installed Mingw32 in d:\mingw-2.0.0, I also created a
Mingw-packages directory called d:\mingw-packages. The install, then,
Since I installed Mingw32 in c:\mingw, I also created a
Mingw-packages directory called c:\mingw-packages. The install, then,
is as easy as this:
<cygwin shell>
$ cd d:/mingw-packages
<msys shell>
$ cd c:/mingw-packages
$ unzip readline-4.2-20010727.zip
[lots of inflating...]
There is no need to adjust your execution path for this package as we
are only using a library out of here. However, do remember the
directory name, as you will need it later.
Done. On to the next packages.
* Install GnuWin32 Packages
The GnuWin32 project is a collections of open source programs and
libraries ported to Windows. These also work well with the Mingw
compiler, and in fact Icarus Verilog uses a few libraries from this
compiler, and in fact Icarus Verilog uses a few pieces from this
collection.
You will need these gnuwin32 packages to compile Icarus Verilog:
<http://gnuwin32.sourceforge.net>
bzip2-1.0.2-lib.zip
bzip2-1.0.2-bin.zip
zlib-1.1.4-lib.zip
zlib-1.1.4-bin.zip
bzip2-1.0.3.exe
zlib-1.2.3.exe
gperf-3.0.1.exe
bison-2.1.exe
flex-2.5.4a.exe
I suggest creating a common directory for holding all your gnuwin32
packages. I use D:\gnuwin32.
packages. I use C:\gnuwin32. The download page at the gnuwin32 site
has a "setup" link for each of these packages. Click the setup to
download the installer for each of the desired programes, then execute
the downloaded .exe files to invoke the installer. Install into the
c:\gunwin32 directory.
After downloading these packages, put the .zip files in your gnuwin32
directory and install them like so:
NOTES:
You need the binaries and the developer files, but you do not
need the source to these packages. The installer gives you the
choice.
<cygwin shell>
$ cd d:/gnuwin32
$ unzip bzip2-1.0.2-bin.zip
[lots of inflating...]
$ unzip bzip2-1.0.2-lib.zip
[lots of inflating...]
$ unzip zlib-1.1.4-bin.zip
[lots of inflating...]
$ unzip zlib-1.1.4-lib.zip
[lots of inflating...]
Done.
After you are done installing the gnuwin32 tools, you should add the
c:\gnuwin32\bin directory (assuming you installed in c:\gnuwin32) to
your Windows path. The msys shell will pick up your Windows path.
* Unpack Icarus Verilog source
Unpack the compressed tar file (.tar.gz) of the source with a command
like this:
$ gunzip -d verilog-20030303.tar.gz | tar xvf -
$ gunzip -d verilog-xxxxxxxx.tar.gz | tar xvf -
This will create a directory "verilog-20030303" that contains all the
This will create a directory "verilog-xxxxxxxx" that contains all the
source for Icarus Verilog. Descend into that directory, as that is
where we will work from now on.
$ cd verilog-20030303
$ cd verilog-xxxxxxxx
NOTE:
NOTES:
The exact name of the file will vary according to the
snapshot. The 20030303 name is only an example.
* Select the mingw compilers
Unpack the source into a directory that has no spaces. The
makefiles included in the source get confused by white space in
directory names.
In your cygwin window, if you type "which c++" you might get the
response path "/usr/bin/c++" which is the cygwin compiler. This is not
the one we want to use, however. Tell the shell where the mingw
compilers are by setting the search path like so:
* Preconfigure Icarus Verilog (Not normally needed)
$ PATH=/cygdrive/d/mingw-2.0.0/bin:$PATH
Under certain cases, you may need to "preconfigure" the Icarus Verilog
source tree. You should only need to do this if you are getting the
Icarus Verilog source tree from CVS, or you are using an existing
source tree that you've patched to cause configure.in files to change.
This assumes that you installed mingw in D:\mingw-2.0.0. The actual
programs are in the bin directory under the root. After this command,
check that you are now getting the right compilers with this "which"
command:
NOTE: If you are building from a fresh, bundled source tree that
you downloaded from an FTP site, then SKIP THIS STEP. Go on to
the "Configure Icarus Verilog" step below.
$ which c++
/cygdrive/d/mingw-2.0.0/bin/c++
First, remove any autom4te.cache directories that may exist in your
source tree. These can make a mess of autoconf runs. Then, generate
configure scripts with this command:
Good!
$ sh autoconf.sh
This script will run the "autoconf" command (part of the msysDTK) to
generate all the necessary "configure" scripts. This will take a few
minutes. This should go smoothly.
* Configure Icarus Verilog
@ -215,10 +216,10 @@ without white space.
Now, configure the source to make the makefiles and configuration
details. Run these commands:
$ CPPFLAGS="-Id:/gnuwin32/include -Id:/mingw-packages/include"
$ LDFLAGS="-Ld:/gnuwin32/lib -Ld:/mingw-packages/include"
$ CPPFLAGS="-Ic:/gnuwin32/include -Ic:/mingw-packages/include"
$ LDFLAGS="-Lc:/gnuwin32/lib -Lc:/mingw-packages/lib"
$ export CPPFLAGS LDFLAGS
$ ./configure --prefix=d:/iverilog
$ ./configure --prefix=c:/iverilog
NOTES:
The CPPFLAGS and LDFLAGS variables tell configure where
@ -267,10 +268,10 @@ directory you chose) and away you go.
You may find that you need to put some of the prerequisite DLLs into
the d:\iverilog\bin directory. These include:
d:\mingw-2.0.0\bin\mingw10.dll
d:\mingw-packages\bin\libreadline.dll
d:\gnuwin32\bin\bzip2.dll
d:\gnuwin32\bin\zlib.dll
c:\mingw\bin\mingw10.dll
c:\mingw-packages\bin\libreadline.dll
c:\gnuwin32\bin\bzip2.dll
c:\gnuwin32\bin\zlib.dll
If you already have these in your Windows path (i.e. your system32
directory) then you do not need to copy them into the iverilog
@ -279,14 +280,14 @@ files.
* Running Icarus Verilog
Finally, put the D:\iverilog\bin directory in your Windows path, and
Finally, put the C:\iverilog\bin directory in your Windows path, and
you should be able to run the iverilog and vvp commands to your
heart's content.
Currently, the iverilog.exe uses the path to itself to locate the
libraries and modules associated with itself. In other words, if you
execute the D:\iverilog\bin\iverilog.exe program, it will locate its
subparts in the D:\iverilog directory and subdirectories below
execute the C:\iverilog\bin\iverilog.exe program, it will locate its
subparts in the C:\iverilog directory and subdirectories below
that. This means you can move the Icarus Verilog installation by
simply moving the root directory and all its contents.

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_assign.cc,v 1.18 2004/08/28 15:08:31 steve Exp $"
#ident "$Id: net_assign.cc,v 1.18.2.3 2006/05/02 02:00:15 steve Exp $"
#endif
# include "config.h"
@ -45,6 +45,7 @@ NetAssign_::NetAssign_(NetNet*s)
lwid_ = sig_->pin_count();
sig_->incr_lref();
more = 0;
mem_lref_ = false;
}
NetAssign_::NetAssign_(NetMemory*s)
@ -53,6 +54,7 @@ NetAssign_::NetAssign_(NetMemory*s)
loff_ = 0;
lwid_ = mem_->width();
more = 0;
mem_lref_ = false;
}
NetAssign_::NetAssign_(NetVariable*s)
@ -61,6 +63,7 @@ NetAssign_::NetAssign_(NetVariable*s)
loff_ = 0;
lwid_ = 0;
more = 0;
mem_lref_ = false;
}
NetAssign_::~NetAssign_()
@ -71,6 +74,14 @@ NetAssign_::~NetAssign_()
sig_->type(NetNet::WIRE);
}
if (mem_) {
NetNet*exp = mem_->reg_from_explode();
if (exp && mem_lref_) {
exp->decr_lref();
if (turn_sig_to_wire_on_release_ && exp->peek_lref() == 0)
exp->type(NetNet::WIRE);
}
}
assert( more == 0 );
if (bmux_) delete bmux_;
}
@ -111,7 +122,10 @@ perm_string NetAssign_::name() const
NetNet* NetAssign_::sig() const
{
return sig_;
if (mem_)
return 0;
else
return sig_;
}
NetMemory* NetAssign_::mem() const
@ -124,6 +138,16 @@ NetVariable* NetAssign_::var() const
return var_;
}
void NetAssign_::incr_mem_lref()
{
if (! mem_lref_) {
assert(mem_);
NetNet*exp = mem_->reg_from_explode();
assert(exp);
exp->incr_lref();
mem_lref_ = true;
}
}
void NetAssign_::set_part(unsigned lo, unsigned lw)
{
@ -261,6 +285,15 @@ NetAssignNB::~NetAssignNB()
/*
* $Log: net_assign.cc,v $
* Revision 1.18.2.3 2006/05/02 02:00:15 steve
* Fix uninitialized mem_lref_ member.
*
* Revision 1.18.2.2 2006/04/16 19:26:38 steve
* Fix handling of exploded memories with partial or missing resets.
*
* Revision 1.18.2.1 2006/03/12 07:34:17 steve
* Fix the memsynth1 case.
*
* Revision 1.18 2004/08/28 15:08:31 steve
* Do not change reg to wire in NetAssign_ unless synthesizing.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_design.cc,v 1.45 2004/10/04 01:10:54 steve Exp $"
#ident "$Id: net_design.cc,v 1.45.2.1 2006/10/04 00:34:45 steve Exp $"
#endif
# include "config.h"
@ -279,7 +279,7 @@ void NetScope::run_defparams(Design*des)
continue;
}
bool flag = targ_scope->replace_parameter(perm_name, val);
bool flag = targ_scope->replace_parameter(perm_name, val->dup_expr());
if (! flag) {
cerr << val->get_line() << ": warning: parameter "
<< perm_name << " not found in "
@ -618,6 +618,9 @@ void Design::delete_process(NetProcTop*top)
/*
* $Log: net_design.cc,v $
* Revision 1.45.2.1 2006/10/04 00:34:45 steve
* Fix a dangling reference to NetEParam objects in defparams.
*
* Revision 1.45 2004/10/04 01:10:54 steve
* Clean up spurious trailing white space.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_link.cc,v 1.14 2004/02/18 17:11:56 steve Exp $"
#ident "$Id: net_link.cc,v 1.14.2.6 2006/08/23 04:09:14 steve Exp $"
#endif
# include "config.h"
@ -40,30 +40,33 @@ void connect(Nexus*l, Link&r)
if (l == r.nexus_)
return;
Nexus*tmp = r.nexus_;
while (Link*cur = tmp->list_) {
tmp->list_ = cur->next_;
cur->nexus_ = 0;
cur->next_ = 0;
cur->prev_ = 0;
l->relink(cur);
}
l->driven_ = Nexus::NO_GUESS;
assert(tmp->list_ == 0);
delete tmp;
}
void connect(Link&l, Link&r)
{
assert(&l != &r);
connect(l.nexus_, r);
if (r.is_linked() && !l.is_linked())
connect(r.nexus_, l);
else if (r.nexus_->list_len_ > l.nexus_->list_len_)
connect(r.nexus_, l);
else
connect(l.nexus_, r);
}
Link::Link()
: dir_(PASSIVE), drive0_(STRONG), drive1_(STRONG), init_(verinum::Vx),
inst_(0), next_(0), nexus_(0)
inst_(0), next_(0), prev_(0), nexus_(0)
{
(new Nexus()) -> relink(this);
}
@ -215,6 +218,7 @@ Nexus::Nexus()
{
name_ = 0;
list_ = 0;
list_len_ = 0;
driven_ = NO_GUESS;
t_cookie_ = 0;
}
@ -241,6 +245,18 @@ verinum::V Nexus::get_init() const
return verinum::Vz;
}
int Nexus::is_driven() const
{
int count = 0;
for (Link*cur = list_ ; cur ; cur = cur->next_) {
if (cur->get_dir() == Link::OUTPUT)
count += 1;
}
return count;
}
void Nexus::unlink(Link*that)
{
if (name_) {
@ -254,22 +270,32 @@ void Nexus::unlink(Link*that)
driven_ = NO_GUESS;
assert(that);
assert(that->nexus_ == this);
if (list_ == that) {
assert(that->prev_ == 0);
// Move the second item the front of the list.
list_ = that->next_;
if (list_)
list_->prev_ = 0;
list_len_ -= 1;
// Clear the pointers for the link.
that->next_ = 0;
that->prev_ = 0;
that->nexus_ = 0;
return;
}
Link*cur = list_;
while (cur->next_ != that) {
assert(cur->next_);
cur = cur->next_;
}
Link*cur = that->prev_;
assert(cur->nexus_ == this);
cur->next_ = that->next_;
if (cur->next_)
cur->next_->prev_ = cur;
that->nexus_ = 0;
that->next_ = 0;
that->prev_ = 0;
list_len_ -= 1;
}
void Nexus::relink(Link*that)
@ -287,8 +313,13 @@ void Nexus::relink(Link*that)
assert(that->nexus_ == 0);
assert(that->next_ == 0);
that->next_ = list_;
that->prev_ = 0;
if (that->next_)
that->next_->prev_ = that;
that->nexus_ = this;
list_ = that;
list_len_ += 1;
}
Link* Nexus::first_nlink()
@ -360,8 +391,9 @@ const char* Nexus::name() const
obj->name() << " pin " << pin << "(" <<
lnk->get_name() << "<" << lnk->get_inst() << ">)"
" type=" << typeid(*obj).name() << "?" << endl;
return 0;
}
assert(sig);
ostringstream tmp;
tmp << sig->name();
@ -378,6 +410,7 @@ const char* Nexus::name() const
NexusSet::NexusSet()
{
items_ = 0;
index_ = 0;
nitems_ = 0;
}
@ -386,8 +419,11 @@ NexusSet::~NexusSet()
if (nitems_ > 0) {
assert(items_ != 0);
delete[] items_;
assert(index_ != 0);
delete[] index_;
} else {
assert(items_ == 0);
assert(index_ == 0);
}
}
@ -396,25 +432,44 @@ unsigned NexusSet::count() const
return nitems_;
}
/*
* Add the Nexus to the nexus set at the *end* of the array. This
* preserves order, which is used in a few cases by the
* synthesizer. But for efficiency, also create a sorted index.
*/
void NexusSet::add(Nexus*that)
{
/* Handle the special case that the set is empty. */
if (nitems_ == 0) {
assert(items_ == 0);
assert(index_ == 0);
items_ = (Nexus**)malloc(sizeof(Nexus*));
items_[0] = that;
index_ = (unsigned*)malloc(sizeof(unsigned));
index_[0] = 0;
nitems_ = 1;
return;
}
unsigned ptr = bsearch_(that);
if ((ptr < nitems_) && (items_[ptr] == that))
if (ptr < nitems_ && items_[index_[ptr]] == that) {
assert(items_[index_[ptr]] == that);
return;
}
items_ = (Nexus**)realloc(items_, (nitems_+1) * sizeof(Nexus*));
for (unsigned idx = nitems_ ; idx > ptr ; idx -= 1)
items_[idx] = items_[idx-1];
items_ = (Nexus**) realloc(items_, (nitems_+1) * sizeof(Nexus*));
index_ = (unsigned*)realloc(index_, (nitems_+1) * sizeof(unsigned));
items_[nitems_] = that;
unsigned dest = nitems_;
for (unsigned idx = ptr ; idx < nitems_ ; idx += 1) {
unsigned tmp = index_[idx];
index_[idx] = dest;
dest = tmp;
}
index_[nitems_] = dest;
items_[ptr] = that;
nitems_ += 1;
}
@ -430,20 +485,31 @@ void NexusSet::rem(Nexus*that)
return;
unsigned ptr = bsearch_(that);
if ((ptr >= nitems_) || (items_[ptr] != that))
if (ptr >= nitems_ || items_[index_[ptr]] != that)
return;
if (nitems_ == 1) {
free(items_);
free(index_);
items_ = 0;
index_ = 0;
nitems_ = 0;
return;
}
for (unsigned idx = ptr ; idx < (nitems_-1) ; idx += 1)
unsigned index_ptr = index_[ptr];
for (unsigned idx = index_ptr ; idx < (nitems_-1) ; idx += 1)
items_[idx] = items_[idx+1];
items_ = (Nexus**)realloc(items_, (nitems_-1) * sizeof(Nexus*));
for (unsigned idx = ptr ; idx < (nitems_-1) ; idx += 1)
index_[idx] = index_[idx+1];
for (unsigned idx = 0 ; idx < (nitems_-1) ; idx += 1)
if (index_[idx] > index_ptr)
index_[idx] -= 1;
items_ = (Nexus**) realloc(items_, (nitems_-1) * sizeof(Nexus*));
index_ = (unsigned*)realloc(index_, (nitems_-1) * sizeof(unsigned));
nitems_ -= 1;
}
@ -459,16 +525,37 @@ Nexus* NexusSet::operator[] (unsigned idx) const
return items_[idx];
}
/*
* This method uses binary search to locate the item in the list of
* nexus pointers. If the item is in the set, then this method returns
* the index where it exists in the *index* array. If the item is not
* in the set, the index points to where in the array the item should go.
*/
unsigned NexusSet::bsearch_(Nexus*that) const
{
for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) {
if (items_[idx] < that)
continue;
return idx;
unsigned low = 0, hig = nitems_;
while (low < hig) {
unsigned mid = (low + hig) / 2;
if (mid == hig) mid -= 1;
assert(mid >= low);
assert(mid < hig);
if (items_[index_[mid]] == that) {
return mid;
} else if (items_[index_[mid]] > that) {
hig = mid;
} else {
low = mid+1;
}
}
return nitems_;
assert(low == hig);
assert(low == nitems_ || items_[index_[low]] >= that);
return low;
}
bool NexusSet::contains(const NexusSet&that) const
@ -477,7 +564,7 @@ bool NexusSet::contains(const NexusSet&that) const
unsigned where = bsearch_(that[idx]);
if (where == nitems_)
return false;
if (items_[where] != that[idx])
if (items_[index_[where]] != that[idx])
return false;
}
@ -490,7 +577,7 @@ bool NexusSet::intersect(const NexusSet&that) const
unsigned where = bsearch_(that[idx]);
if (where == nitems_)
continue;
if (items_[where] == that[idx])
if (items_[index_[where]] == that[idx])
return true;
}
@ -499,6 +586,24 @@ bool NexusSet::intersect(const NexusSet&that) const
/*
* $Log: net_link.cc,v $
* Revision 1.14.2.6 2006/08/23 04:09:14 steve
* missing sig diagnostics.
*
* Revision 1.14.2.5 2006/08/15 03:41:24 steve
* Improve performance of unlink of heavily connected nexa.
*
* Revision 1.14.2.4 2006/08/08 02:17:48 steve
* Improved nexus management performance.
*
* Revision 1.14.2.3 2006/07/23 19:42:33 steve
* Handle statement output override better in blocks.
*
* Revision 1.14.2.2 2006/01/27 02:05:46 steve
* Speed up processing of connect when one side is empty.
*
* Revision 1.14.2.1 2005/09/25 23:30:31 steve
* More predictable ordering of items in NexusSet.
*
* Revision 1.14 2004/02/18 17:11:56 steve
* Use perm_strings for named langiage items.
*
@ -523,35 +628,5 @@ bool NexusSet::intersect(const NexusSet&that) const
* Revision 1.7 2002/06/24 01:49:39 steve
* Make link_drive_constant cache its results in
* the Nexus, to improve cprop performance.
*
* Revision 1.6 2002/04/21 04:59:08 steve
* Add support for conbinational events by finding
* the inputs to expressions and some statements.
* Get case and assignment statements working.
*
* Revision 1.5 2001/07/25 03:10:49 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.4 2000/10/06 23:46:50 steve
* ivl_target updates, including more complete
* handling of ivl_nexus_t objects. Much reduced
* dependencies on pointers to netlist objects.
*
* Revision 1.3 2000/08/26 00:54:03 steve
* Get at gate information for ivl_target interface.
*
* Revision 1.2 2000/07/14 06:12:57 steve
* Move inital value handling from NetNet to Nexus
* objects. This allows better propogation of inital
* values.
*
* Clean up constant propagation a bit to account
* for regs that are not really values.
*
* Revision 1.1 2000/06/25 19:59:42 steve
* Redesign Links to include the Nexus class that
* carries properties of the connected set of links.
*
*/

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_nex_input.cc,v 1.12 2004/09/04 04:24:15 steve Exp $"
#ident "$Id: net_nex_input.cc,v 1.12.2.1 2006/05/21 21:58:47 steve Exp $"
#endif
# include "config.h"
@ -138,7 +138,8 @@ NexusSet* NetESFunc::nex_input()
NexusSet* NetESignal::nex_input()
{
NexusSet*result = new NexusSet;
for (unsigned idx = 0 ; idx < net_->pin_count() ; idx += 1)
assert(msi_ <= net_->pin_count());
for (unsigned idx = lsi_ ; idx <= msi_ ; idx += 1)
result->add(net_->pin(idx).nexus());
return result;
@ -398,6 +399,9 @@ NexusSet* NetWhile::nex_input()
/*
* $Log: net_nex_input.cc,v $
* Revision 1.12.2.1 2006/05/21 21:58:47 steve
* NetESignal input is only selected bits.
*
* Revision 1.12 2004/09/04 04:24:15 steve
* PR1026: assignment statements can have sensitivities in the l-values.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_nex_output.cc,v 1.11 2004/09/16 03:17:33 steve Exp $"
#ident "$Id: net_nex_output.cc,v 1.11.2.8 2006/08/08 02:17:48 steve Exp $"
#endif
# include "config.h"
@ -47,10 +47,55 @@ void NetAssignBase::nex_output(NexusSet&out)
{
for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) {
if (NetNet*lsig = cur->sig()) {
if (cur->bmux()) {
for (unsigned idx = 0; idx < lsig->pin_count(); idx += 1) {
out.add(lsig->pin(idx).nexus());
}
continue;
}
/* Handle l-value signals. We don't need to worry
here about whether there is a bmux, because the
synthesizer will detect that mux and create a
decoder between the expression and the signal. */
for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) {
unsigned off = cur->get_loff() + idx;
out.add(lsig->pin(off).nexus());
}
} else if (NetMemory*lmem = cur->mem()) {
/* Memories here are treated as a bunch of reg
devices. Use the explode_to_reg method to get
access to the FF version of the memory and use
that in our l-value management. */
NetNet*tmp = lmem->explode_to_reg();
if (NetEConst*ae = dynamic_cast<NetEConst*>(cur->bmux())) {
/* The address is constant, so simply
connect to the right pins and we are
done. */
long adr_s = ae->value().as_long();
unsigned adr = lmem->index_to_address(adr_s) * lmem->width();
if (adr >= lmem->count()*lmem->width()) {
/* Skip assignments with constant
addresses that are outside the
range of memories. */
} else {
for (unsigned idx=0; idx<cur->lwidth(); idx += 1)
out.add(tmp->pin(adr+idx).nexus());
}
} else {
/* Put all the bits of the memory into the
set. The synthesis will generate a
decoder to handle this. */
for (unsigned idx = 0; idx < tmp->pin_count(); idx+=1)
out.add(tmp->pin(idx).nexus());
}
} else {
/* Quoting from netlist.h comments for class NetMemory:
* "This is not a node because memory objects can only be
@ -69,11 +114,11 @@ void NetBlock::nex_output(NexusSet&out)
if (last_ == 0)
return;
NetProc*cur = last_;
NetProc*cur = last_->next_;
do {
cur = cur->next_;
cur->nex_output(out);
} while (cur != last_);
cur = cur->next_;
} while (cur != last_->next_);
}
void NetCase::nex_output(NexusSet&out)
@ -122,6 +167,30 @@ void NetWhile::nex_output(NexusSet&out)
/*
* $Log: net_nex_output.cc,v $
* Revision 1.11.2.8 2006/08/08 02:17:48 steve
* Improved nexus management performance.
*
* Revision 1.11.2.7 2006/06/02 23:42:48 steve
* Compilation warnings.
*
* Revision 1.11.2.6 2006/06/01 03:01:48 steve
* Handle condit clauses with unassigned outputs.
*
* Revision 1.11.2.5 2006/05/18 01:47:12 steve
* Fix synthesis of l-value bit select in block.
*
* Revision 1.11.2.4 2006/05/05 01:56:36 steve
* Handle memory assignments out of range during synthesis
*
* Revision 1.11.2.3 2006/04/16 19:26:38 steve
* Fix handling of exploded memories with partial or missing resets.
*
* Revision 1.11.2.2 2006/03/12 07:34:17 steve
* Fix the memsynth1 case.
*
* Revision 1.11.2.1 2006/01/18 01:23:23 steve
* Rework l-value handling to allow for more l-value type flexibility.
*
* Revision 1.11 2004/09/16 03:17:33 steve
* net_output handles l-value concatenations.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_scope.cc,v 1.33 2004/10/04 01:10:54 steve Exp $"
#ident "$Id: net_scope.cc,v 1.33.2.1 2005/02/19 16:39:31 steve Exp $"
#endif
# include "config.h"
@ -194,7 +194,7 @@ const NetFuncDef* NetScope::func_def() const
void NetScope::set_module_name(perm_string n)
{
assert(type_ == MODULE);
module_name_ = n; /* NOTE: n mus have been permallocated. */
module_name_ = n; /* NOTE: n must have been permallocated. */
}
perm_string NetScope::module_name() const
@ -467,6 +467,9 @@ string NetScope::local_hsymbol()
/*
* $Log: net_scope.cc,v $
* Revision 1.33.2.1 2005/02/19 16:39:31 steve
* Spellig fixes.
*
* Revision 1.33 2004/10/04 01:10:54 steve
* Clean up spurious trailing white space.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netlist.cc,v 1.226 2004/10/04 01:10:54 steve Exp $"
#ident "$Id: netlist.cc,v 1.226.2.7 2006/04/23 04:26:14 steve Exp $"
#endif
# include "config.h"
@ -229,7 +229,7 @@ NetNode::~NetNode()
NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
: NetObj(s, n, npins), sig_next_(0), sig_prev_(0),
type_(t), port_type_(NOT_A_PORT), signed_(false), msb_(npins-1), lsb_(0),
local_flag_(false), eref_count_(0), lref_count_(0)
local_flag_(false), eref_count_(0), lref_count_(0), mref_(0)
{
assert(s);
@ -270,7 +270,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, long ms, long ls)
: NetObj(s, n, ((ms>ls)?ms-ls:ls-ms) + 1),
sig_next_(0), sig_prev_(0), type_(t),
port_type_(NOT_A_PORT), signed_(false), msb_(ms), lsb_(ls),
local_flag_(false), eref_count_(0), lref_count_(0)
local_flag_(false), eref_count_(0), lref_count_(0), mref_(0)
{
assert(s);
@ -322,6 +322,14 @@ NetNet::~NetNet()
dump_net(cerr, 4);
}
assert(lref_count_ == 0);
if (mref_ != 0) {
cerr << get_line() << ": internal error: attempt to delete "
<< "signal ``" << name() << "'' which has "
<< "memory explode references." << endl;
dump_net(cerr, 4);
}
assert(mref_ == 0);
if (scope())
scope()->rem_signal(this);
@ -462,6 +470,23 @@ unsigned NetNet::get_refs() const
return lref_count_ + eref_count_;
}
void NetNet::mref(NetMemory*mem)
{
assert(mref_ == 0);
assert(mem != 0);
mref_ = mem;
}
NetMemory*NetNet::mref()
{
return mref_;
}
const NetMemory* NetNet::mref() const
{
return mref_;
}
NetSubnet::NetSubnet(NetNet*sig, unsigned off, unsigned wid)
: NetNet(sig->scope(), sig->scope()->local_symbol(), sig->type(), wid)
@ -533,6 +558,8 @@ const NetScope* NetProcTop::scope() const
NetFF::NetFF(NetScope*s, perm_string n, unsigned wid)
: NetNode(s, n, 8 + 2*wid)
{
demux_ = 0;
pin_Clock().set_dir(Link::INPUT);
pin_Clock().set_name(perm_string::literal("Clock"), 0);
pin_Enable().set_dir(Link::INPUT);
@ -684,6 +711,118 @@ const verinum& NetFF::sset_value() const
return sset_value_;
}
unsigned NetDecode::width() const
{
return width_;
}
unsigned NetDecode::awidth() const
{
return pin_count();
}
NetDemux::NetDemux(NetScope*s, perm_string name,
unsigned bus_width, unsigned address_width, unsigned size)
: NetNode(s, name, bus_width*2+address_width+bus_width/size)
{
width_ = bus_width;
awidth_ = address_width;
size_ = size;
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
pin_Q(idx).set_dir(Link::OUTPUT);
pin_Q(idx).set_name(perm_string::literal("Q"), idx);
}
for (unsigned idx = 0 ; idx < width_ ; idx += 1) {
pin_Data(idx).set_dir(Link::INPUT);
pin_Data(idx).set_name(perm_string::literal("Data"), idx);
}
for (unsigned idx = 0 ; idx < awidth_ ; idx += 1) {
pin_Address(idx).set_dir(Link::INPUT);
pin_Address(idx).set_name(perm_string::literal("Address"), idx);
}
for (unsigned idx = 0 ; idx < width_/size_ ; idx += 1) {
pin_WriteData(idx).set_dir(Link::INPUT);
pin_WriteData(idx).set_name(perm_string::literal("Writedata"), idx);
}
}
NetDemux::~NetDemux()
{
}
unsigned NetDemux::width() const
{
return width_;
}
unsigned NetDemux::awidth() const
{
return awidth_;
}
unsigned NetDemux::size() const
{
return size_;
}
Link& NetDemux::pin_Q(unsigned idx)
{
assert(idx < width_);
return pin(idx);
}
const Link& NetDemux::pin_Q(unsigned idx) const
{
assert(idx < width_);
return pin(idx);
}
Link& NetDemux::pin_Data(unsigned idx)
{
assert(idx < width_);
return pin(width_+idx);
}
const Link& NetDemux::pin_Data(unsigned idx) const
{
assert(idx < width_);
return pin(width_+idx);
}
Link& NetDemux::pin_Address(unsigned idx)
{
assert(idx < awidth_);
return pin(width_+width_+idx);
}
const Link& NetDemux::pin_Address(unsigned idx) const
{
assert(idx < awidth_);
return pin(width_+width_+idx);
}
Link& NetDemux::pin_WriteData(unsigned idx)
{
assert(idx < width_/size_);
return pin(width_+width_+awidth_+idx);
}
const Link& NetDemux::pin_WriteData(unsigned idx) const
{
assert(idx < width_/size_);
return pin(width_+width_+awidth_+idx);
}
NetDecode* NetFF::get_demux()
{
return demux_;
}
const NetDecode* NetFF::get_demux() const
{
return demux_;
}
/*
* The NetAddSub class represents an LPM_ADD_SUB device. The pinout is
@ -1060,6 +1199,40 @@ const Link& NetCompare::pin_DataB(unsigned idx) const
return pin(8+width_+idx);
}
NetDecode::NetDecode(NetScope*s, perm_string name, NetFF*mem,
unsigned awid, unsigned word_width)
: NetNode(s, name, awid)
{
width_ = word_width;
assert( mem->width() % width_ == 0 );
ff_ = mem;
ff_->demux_ = this;
make_pins_(awid);
}
NetDecode::~NetDecode()
{
}
void NetDecode::make_pins_(unsigned awid)
{
for (unsigned idx = 0 ; idx < awid ; idx += 1) {
pin(idx).set_dir(Link::INPUT);
pin(idx).set_name(perm_string::literal("Address"), idx);
}
}
Link& NetDecode::pin_Address(unsigned idx)
{
return pin(idx);
}
const Link& NetDecode::pin_Address(unsigned idx) const
{
return pin(idx);
}
NetDivide::NetDivide(NetScope*sc, perm_string n, unsigned wr,
unsigned wa, unsigned wb)
: NetNode(sc, n, wr+wa+wb),
@ -1385,10 +1558,7 @@ const Link& NetMux::pin_Data(unsigned w, unsigned s) const
return pin(2+width_+swidth_+s*width_+w);
}
NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid)
: NetNode(s, n, 3+2*mem->width()+awid),
mem_(mem), awidth_(awid)
void NetRamDq::make_pins_(unsigned wid)
{
pin(0).set_dir(Link::INPUT); pin(0).set_name(perm_string::literal("InClock"), 0);
pin(1).set_dir(Link::INPUT); pin(1).set_name(perm_string::literal("OutClock"), 0);
@ -1399,39 +1569,49 @@ NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid)
pin(3+idx).set_name(perm_string::literal("Address"), idx);
}
for (unsigned idx = 0 ; idx < width() ; idx += 1) {
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
pin(3+awidth_+idx).set_dir(Link::INPUT);
pin(3+awidth_+idx).set_name(perm_string::literal("Data"), idx);
}
for (unsigned idx = 0 ; idx < width() ; idx += 1) {
pin(3+awidth_+width()+idx).set_dir(Link::OUTPUT);
pin(3+awidth_+width()+idx).set_name(perm_string::literal("Q"), idx);
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
pin(3+awidth_+wid+idx).set_dir(Link::OUTPUT);
pin(3+awidth_+wid+idx).set_name(perm_string::literal("Q"), idx);
}
}
NetRamDq::NetRamDq(NetScope*s, perm_string n, NetMemory*mem, unsigned awid)
: NetNode(s, n, 3+2*mem->width()+awid),
mem_(mem), awidth_(awid)
{
make_pins_(mem->width());
next_ = mem_->ram_list_;
mem_->ram_list_ = this;
}
NetRamDq::~NetRamDq()
{
if (mem_->ram_list_ == this) {
mem_->ram_list_ = next_;
if (mem_) {
if (mem_->ram_list_ == this) {
mem_->ram_list_ = next_;
} else {
NetRamDq*cur = mem_->ram_list_;
while (cur->next_ != this) {
assert(cur->next_);
cur = cur->next_;
} else {
NetRamDq*cur = mem_->ram_list_;
while (cur->next_ != this) {
assert(cur->next_);
cur = cur->next_;
}
assert(cur->next_ == this);
cur->next_ = next_;
}
assert(cur->next_ == this);
cur->next_ = next_;
}
}
unsigned NetRamDq::width() const
{
return mem_->width();
if (mem_) return mem_->width();
return 0;
}
unsigned NetRamDq::awidth() const
@ -1441,7 +1621,13 @@ unsigned NetRamDq::awidth() const
unsigned NetRamDq::size() const
{
return mem_->count();
if (mem_) return mem_->count();
return 0;
}
NetMemory* NetRamDq::mem()
{
return mem_;
}
const NetMemory* NetRamDq::mem() const
@ -2003,6 +2189,7 @@ NetMemory::NetMemory(NetScope*sc, perm_string n, long w, long s, long e)
: width_(w), idxh_(s), idxl_(e), ram_list_(0), scope_(sc)
{
name_ = n;
explode_ = 0;
scope_->add_memory(this);
}
@ -2033,7 +2220,25 @@ unsigned NetMemory::index_to_address(long idx) const
return idx - idxl_;
}
NetNet* NetMemory::explode_to_reg()
{
if (explode_)
return explode_;
explode_ = new NetNet(scope_, name_, NetNet::REG, count()*width_);
//explode_->incr_lref();
return explode_;
}
NetNet* NetMemory::reg_from_explode()
{
return explode_;
}
const NetNet* NetMemory::reg_from_explode() const
{
return explode_;
}
NetEMemory* NetEMemory::dup_expr() const
{
@ -2281,6 +2486,27 @@ const NetProc*NetTaskDef::proc() const
/*
* $Log: netlist.cc,v $
* Revision 1.226.2.7 2006/04/23 04:26:14 steve
* Constant propagate addresses through NetRamDq read ports.
*
* Revision 1.226.2.6 2006/04/16 19:26:38 steve
* Fix handling of exploded memories with partial or missing resets.
*
* Revision 1.226.2.5 2006/03/26 23:09:22 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.226.2.4 2006/03/16 05:40:18 steve
* Fix crash when memory exploding doesnot work
*
* Revision 1.226.2.3 2006/03/12 07:34:17 steve
* Fix the memsynth1 case.
*
* Revision 1.226.2.2 2006/02/19 00:11:32 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.226.2.1 2006/01/18 01:23:23 steve
* Rework l-value handling to allow for more l-value type flexibility.
*
* Revision 1.226 2004/10/04 01:10:54 steve
* Clean up spurious trailing white space.
*

312
netlist.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netlist.h,v 1.321 2004/10/04 01:10:54 steve Exp $"
#ident "$Id: netlist.h,v 1.321.2.23 2006/08/15 03:41:24 steve Exp $"
#endif
/*
@ -48,6 +48,7 @@ class ostream;
class Design;
class Link;
class Nexus;
class NetMemory;
class NetNode;
class NetProc;
class NetProcTop;
@ -58,12 +59,22 @@ class NetEvProbe;
class NetExpr;
class NetESignal;
class NetEVariable;
class NetFF;
class NetFuncDef;
class NetRamDq;
class NetEvTrig;
class NetEvWait;
struct target;
struct functor_t;
struct sync_accounting_cell {
NetProc*proc;
NetFF*ff;
unsigned pin;
};
/* =========
* A NetObj is anything that has any kind of behavior in the
* netlist. Nodes can be gates, registers, etc. and are linked
@ -215,7 +226,7 @@ class Link {
unsigned inst_;
private:
Link *next_;
Link *next_, *prev_;
Nexus*nexus_;
private: // not implemented
@ -253,6 +264,9 @@ class Nexus {
Link*first_nlink();
const Link* first_nlink()const;
/* Return the number of drivers, or 0 if undriven. */
int is_driven() const;
/* This method returns true if all the possible drivers of
this nexus are constant. It will also return true if there
are no drivers at all. */
@ -267,6 +281,7 @@ class Nexus {
private:
Link*list_;
int list_len_;
void unlink(Link*);
void relink(Link*);
@ -307,6 +322,7 @@ class NexusSet {
private:
Nexus**items_;
unsigned*index_;
unsigned nitems_;
unsigned bsearch_(Nexus*that) const;
@ -424,6 +440,11 @@ class NetNet : public NetObj {
unsigned get_refs() const;
/* This may be and explode of a memory. */
void mref(NetMemory*ref);
NetMemory*mref();
const NetMemory*mref() const;
virtual void dump_net(ostream&, unsigned) const;
private:
@ -448,6 +469,7 @@ class NetNet : public NetObj {
bool local_flag_;
unsigned eref_count_;
unsigned lref_count_;
NetMemory*mref_;
};
/*
@ -581,6 +603,87 @@ class NetCompare : public NetNode {
bool signed_flag_;
};
/*
* A decoder takes an address input and activates (high) the single
* Q bit that is addressed. This can be used, for example, to
* generate an enable for a FF from an array of FFs.
*/
class NetDecode : public NetNode {
public:
NetDecode(NetScope*s, perm_string name, NetFF*mem,
unsigned awid, unsigned word_width);
~NetDecode();
// This is the width of the word. The width of the NetFF mem
// is an even multiple of this.
unsigned width() const;
// This is the width of the address. The address value for the
// base of a word is the address * width().
unsigned awidth() const;
const NetFF*ff() const;
Link& pin_Address(unsigned idx);
const Link& pin_Address(unsigned idx) const;
const Link& pin_Q(unsigned idx) const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
unsigned width_;
NetFF* ff_;
private:
void make_pins_(unsigned awid);
};
/*
* The NetDemux is similar to the NetDecode, except that it is
* combinational. The inputs are an address, Data, and WriteData.
* The Q output is the same as the Data input, except for the bit that
* is addressed by the address input, which gets WriteData instead.
*/
class NetDemux : public NetNode {
public:
NetDemux(NetScope*s, perm_string name,
unsigned bus_width, unsigned address_width,
unsigned size);
~NetDemux();
// This is the width of the bus that passes through the
// device. The address addresses into this width.
unsigned width() const;
// This is the width of the address. The address value for the
// base of a word is the address * width().
unsigned awidth() const;
// This is the number of words in the width that can be
// addressed. This implies (by division) the width of a word.
unsigned size() const;
Link& pin_Address(unsigned idx);
Link& pin_Data(unsigned idx);
Link& pin_Q(unsigned idx);
Link& pin_WriteData(unsigned idx);
const Link& pin_Address(unsigned idx) const;
const Link& pin_Data(unsigned idx) const;
const Link& pin_Q(unsigned idx) const;
const Link& pin_WriteData(unsigned idx) const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
unsigned width_, awidth_, size_;
private:
void make_pins_(unsigned wid, unsigned awid);
};
/*
* This class represents a theoretical (though not necessarily
* practical) integer divider gate. This is not to represent any real
@ -703,10 +806,19 @@ class NetFF : public NetNode {
void sset_value(const verinum&val);
const verinum& sset_value() const;
NetDecode* get_demux();
const NetDecode* get_demux() const;
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
virtual void functor_node(Design*des, functor_t*fun);
private:
// If there is a demux associated with this gate, the demux_
// member will point to the decoder.
friend class NetDecode;
NetDecode*demux_;
private:
verinum aset_value_;
verinum sset_value_;
@ -735,6 +847,7 @@ class NetMemory {
// NetScope*scope();
const NetScope*scope() const { return scope_; };
NetScope*scope() { return scope_; };
// This is the number of memory positions.
unsigned count() const;
@ -744,6 +857,13 @@ class NetMemory {
// that are not zero based.
unsigned index_to_address(long idx) const;
// This method returns a NetNet::REG that has the same number
// of bits as the memory as a whole. This is used to represent
// memories that are synthesized to individual bits.
NetNet* explode_to_reg();
NetNet* reg_from_explode();
const NetNet* reg_from_explode() const;
void dump(ostream&o, unsigned lm) const;
private:
@ -753,12 +873,14 @@ class NetMemory {
long idxl_;
friend class NetRamDq;
NetRamDq* ram_list_;
class NetRamDq* ram_list_;
friend class NetScope;
NetMemory*snext_, *sprev_;
NetScope*scope_;
NetNet*explode_;
private: // not implemented
NetMemory(const NetMemory&);
NetMemory& operator= (const NetMemory&);
@ -878,6 +1000,8 @@ class NetRamDq : public NetNode {
unsigned width() const;
unsigned awidth() const;
unsigned size() const;
NetMemory*mem();
const NetMemory*mem() const;
Link& pin_InClock();
@ -908,11 +1032,15 @@ class NetRamDq : public NetNode {
// that are ports to the attached memory.
unsigned count_partners() const;
void functor_node(Design*des, functor_t*fun);
private:
NetMemory*mem_;
NetRamDq*next_;
unsigned awidth_;
private:
void make_pins_(unsigned wid);
};
/*
@ -1315,7 +1443,7 @@ 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 : public virtual LineInfo {
class NetProc : public virtual LineInfo, public Attrib {
public:
explicit NetProc();
@ -1346,15 +1474,33 @@ class NetProc : public virtual LineInfo {
// process. Most process types are not.
virtual bool is_synchronous();
// synthesize as asynchronous logic, and return true.
virtual bool synth_async(Design*des, NetScope*scope,
const NetNet*nex_map, NetNet*nex_out);
// synthesize as asynchronous logic, and return true. The
// sync_flag is used to tell the async synthesizer that the
// output nex_map is ultimately connected to a DFF Q
// output. This can affect how cycles are handled.
virtual bool synth_sync(Design*des, NetScope*scope, NetFF*ff,
const NetNet*nex_map, NetNet*nex_out,
bool synth_async_noaccum(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out);
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out,
NetNet*accum_in);
// Synthesize synchronous logic, and return true. The nex_out
// is where outputs are actually connected, and the nex_map
// maps nexa to bit positions. The ff is the initial DFF that
// was created to receive the Data inputs. The method *may*
// delete that DFF in favor of multiple smaller devices, but
// in that case it will set the ff argument to nil.
virtual bool synth_sync(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events);
virtual void dump(ostream&, unsigned ind) const;
void dump_proc_attr(ostream&, unsigned ind) const;
private:
friend class NetBlock;
@ -1432,6 +1578,8 @@ class NetAssign_ {
// into a wire.
void turn_sig_to_wire_on_release();
void incr_mem_lref();
// It is possible that l-values can have *inputs*, as well as
// being outputs. For example foo[idx] = ... is the l-value
// (NetAssign_ object) with a foo l-value and the input
@ -1452,6 +1600,7 @@ class NetAssign_ {
bool turn_sig_to_wire_on_release_;
unsigned loff_;
unsigned lwid_;
bool mem_lref_;
};
class NetAssignBase : public NetProc {
@ -1482,13 +1631,24 @@ class NetAssignBase : public NetProc {
// accounts for any grouping of NetAssign_ objects that might happen.
unsigned lwidth() const;
bool synth_async(Design*des, NetScope*scope,
const NetNet*nex_map, NetNet*nex_out);
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out,
NetNet*accum_in);
bool synth_sync(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events);
// This dumps all the lval structures.
void dump_lval(ostream&) const;
virtual void dump(ostream&, unsigned ind) const;
private:
bool synth_async_mem_sync_(Design*des, NetScope*scope,
NetAssign_*cur, NetNet*rsig, unsigned&roff,
NetNet*nex_map, NetNet*nex_out);
private:
NetAssign_*lval_;
NetExpr *rval_;
@ -1549,11 +1709,13 @@ class NetBlock : public NetProc {
// synthesize as asynchronous logic, and return true.
bool synth_async(Design*des, NetScope*scope,
const NetNet*nex_map, NetNet*nex_out);
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in);
bool synth_sync(Design*des, NetScope*scope, NetFF*ff,
const NetNet*nex_map, NetNet*nex_out,
bool synth_sync(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events);
// This version of emit_recurse scans all the statements of
@ -1604,12 +1766,18 @@ class NetCase : public NetProc {
virtual NexusSet* nex_input();
virtual void nex_output(NexusSet&out);
bool synth_async(Design*des, NetScope*scope,
const NetNet*nex_map, NetNet*nex_out);
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
private:
bool synth_async_1hot_(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in,
NetNet*esig, unsigned hot_items);
private:
TYPE type_;
@ -1686,17 +1854,26 @@ class NetCondit : public NetProc {
virtual void nex_output(NexusSet&o);
bool is_asynchronous();
bool synth_async(Design*des, NetScope*scope,
const NetNet*nex_map, NetNet*nex_out);
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum);
bool synth_sync(Design*des, NetScope*scope, NetFF*ff,
const NetNet*nex_map, NetNet*nex_out,
bool synth_sync(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events);
virtual bool emit_proc(struct target_t*) const;
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
private:
int connect_set_clr_range_( struct sync_accounting_cell*nex_ff,
unsigned bits, NetNet*rst,
const verinum&val);
int connect_enable_range_(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
unsigned bits, NetNet*ce);
private:
NetExpr* expr_;
NetProc*if_;
@ -1845,12 +2022,12 @@ class NetEvent : public LineInfo {
NetEvProbe*probes_;
// Use these methods to list the triggers attached to me.
NetEvTrig* trig_;
class NetEvTrig* trig_;
// Use This member to count references by NetEvWait objects.
unsigned waitref_;
struct wcell_ {
NetEvWait*obj;
class NetEvWait*obj;
struct wcell_*next;
};
struct wcell_ *wlist_;
@ -1911,11 +2088,14 @@ class NetEvWait : public NetProc {
virtual void nex_output(NexusSet&out);
virtual bool synth_async(Design*des, NetScope*scope,
const NetNet*nex_map, NetNet*nex_out);
virtual bool synth_async(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out,
NetNet*accum_in);
virtual bool synth_sync(Design*des, NetScope*scope, NetFF*ff,
const NetNet*nex_map, NetNet*nex_out,
virtual bool synth_sync(Design*des, NetScope*scope,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out,
const svector<NetEvProbe*>&events);
virtual void dump(ostream&, unsigned ind) const;
@ -2309,6 +2489,10 @@ class NetWhile : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
bool synth_async(Design*des, NetScope*scope, bool sync_flag,
struct sync_accounting_cell*nex_ff,
NetNet*nex_map, NetNet*nex_out, NetNet*accum_in);
private:
NetExpr* cond_;
NetProc*proc_;
@ -2523,7 +2707,7 @@ class NetEBComp : public NetEBinary {
NetEConst*eval_eqeq_();
NetEConst*eval_less_();
NetEConst*eval_leeq_();
NetEConst*eval_leeq_real_();
NetEConst*eval_leeq_real_(bool gt_flag, bool include_eq_flag);
NetEConst*eval_gt_();
NetEConst*eval_gteq_();
NetEConst*eval_neeq_();
@ -2924,7 +3108,7 @@ class NetEMemory : public NetExpr {
const NetExpr* index() const;
virtual bool set_width(unsigned);
virtual NetNet* synthesize(Design*);
NetExpr* eval_tree();
virtual NetEMemory*dup_expr() const;
@ -3004,6 +3188,7 @@ class NetEBitSel : public NetExpr {
const NetNet* sig() const;
NetEBitSel* dup_expr() const;
NetNet* synthesize(Design*des);
virtual NexusSet* nex_input();
virtual void expr_scan(struct expr_scan_t*) const;
@ -3357,6 +3542,75 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.321.2.23 2006/08/15 03:41:24 steve
* Improve performance of unlink of heavily connected nexa.
*
* Revision 1.321.2.22 2006/08/08 02:17:48 steve
* Improved nexus management performance.
*
* Revision 1.321.2.21 2006/07/23 19:42:33 steve
* Handle statement output override better in blocks.
*
* Revision 1.321.2.20 2006/07/10 00:21:51 steve
* Add support for full_case attribute.
*
* Revision 1.321.2.19 2006/06/23 03:49:46 steve
* synthesis of NetCondit handles partial resets.
*
* Revision 1.321.2.18 2006/06/14 03:02:54 steve
* synthesis for NetEBitSel.
*
* Revision 1.321.2.17 2006/04/23 04:26:14 steve
* Constant propagate addresses through NetRamDq read ports.
*
* Revision 1.321.2.16 2006/04/16 19:26:38 steve
* Fix handling of exploded memories with partial or missing resets.
*
* Revision 1.321.2.15 2006/04/10 03:43:39 steve
* Exploded memories accessed by constant indices.
*
* Revision 1.321.2.14 2006/03/26 23:09:23 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.321.2.13 2006/03/18 18:43:21 steve
* Better error messages when synthesis fails.
*
* Revision 1.321.2.12 2006/03/16 05:40:18 steve
* Fix crash when memory exploding doesnot work
*
* Revision 1.321.2.11 2006/03/12 07:34:17 steve
* Fix the memsynth1 case.
*
* Revision 1.321.2.10 2006/02/19 00:11:32 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.321.2.9 2006/01/21 21:42:31 steve
* When mux has wide select but sparse choices, use 1hot translation.
*
* Revision 1.321.2.8 2006/01/18 01:23:24 steve
* Rework l-value handling to allow for more l-value type flexibility.
*
* Revision 1.321.2.7 2005/12/31 04:28:14 steve
* Fix crashes caused bu synthesis of sqrt32.v.
*
* Revision 1.321.2.6 2005/12/14 00:54:29 steve
* Account for sync vs async muxes.
*
* Revision 1.321.2.5 2005/11/13 22:28:48 steve
* Allow for block output to be set throughout the statements.
*
* Revision 1.321.2.4 2005/09/09 02:17:08 steve
* Evaluate magnitude compare with real operands.
*
* Revision 1.321.2.3 2005/08/22 01:00:41 steve
* Add support for implicit defaults in case and conditions.
*
* Revision 1.321.2.2 2005/08/13 00:45:54 steve
* Fix compilation warnings/errors with newer compilers.
*
* Revision 1.321.2.1 2005/07/06 22:41:34 steve
* Fix compile errors with g++-4.
*
* Revision 1.321 2004/10/04 01:10:54 steve
* Clean up spurious trailing white space.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netmisc.cc,v 1.8 2004/02/20 18:53:35 steve Exp $"
#ident "$Id: netmisc.cc,v 1.8.2.1 2006/05/15 03:55:23 steve Exp $"
#endif
# include "config.h"
@ -72,6 +72,26 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val)
return res;
}
NetNet* reduction_or(Design*des, NetNet*isig)
{
NetScope*scope = isig->scope();
NetLogic*olog = new NetLogic(scope, scope->local_symbol(),
isig->pin_count()+1, NetLogic::OR);
olog->set_line(*isig);
des->add_node(olog);
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1);
osig->local_flag(true);
osig->set_line(*isig);
connect(olog->pin(0), osig->pin(0));
for (unsigned idx = 0 ; idx < isig->pin_count() ; idx += 1)
connect(olog->pin(1+idx), isig->pin(idx));
return osig;
}
NetExpr* elab_and_eval(Design*des, NetScope*scope, const PExpr*pe)
{
@ -90,6 +110,9 @@ NetExpr* elab_and_eval(Design*des, NetScope*scope, const PExpr*pe)
/*
* $Log: netmisc.cc,v $
* Revision 1.8.2.1 2006/05/15 03:55:23 steve
* Fix synthesis of expressions with land of vectors.
*
* Revision 1.8 2004/02/20 18:53:35 steve
* Addtrbute keys are perm_strings.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netmisc.h,v 1.19 2004/03/07 20:04:11 steve Exp $"
#ident "$Id: netmisc.h,v 1.19.2.1 2006/05/15 03:55:23 steve Exp $"
#endif
# include "netlist.h"
@ -57,6 +57,11 @@ extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w);
*/
extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
/*
* Calculate the reduction OR from the input signal.
*/
extern NetNet*reduction_or(Design*des, NetNet*sig);
/*
* In some cases the lval is accessible as a pointer to the head of
* a list of NetAssign_ objects. This function returns the width of
@ -75,6 +80,9 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope, const PExpr*pe);
/*
* $Log: netmisc.h,v $
* Revision 1.19.2.1 2006/05/15 03:55:23 steve
* Fix synthesis of expressions with land of vectors.
*
* Revision 1.19 2004/03/07 20:04:11 steve
* MOre thorough use of elab_and_eval function.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: nodangle.cc,v 1.21 2004/02/20 18:53:35 steve Exp $"
#ident "$Id: nodangle.cc,v 1.21.2.2 2006/08/23 04:08:55 steve Exp $"
#endif
# include "config.h"
@ -109,6 +109,9 @@ void nodangle_f::signal(Design*des, NetNet*sig)
if (sig->get_refs() > 0)
return;
if (sig->mref())
return;
/* Cannot delete the ports of tasks or functions. There are
too many places where they are referenced. */
if ((sig->port_type() != NetNet::NOT_A_PORT)
@ -160,6 +163,9 @@ void nodangle_f::signal(Design*des, NetNet*sig)
if (cursig == 0)
continue;
if (cursig == sig)
continue;
if (cursig->local_flag())
continue;
@ -205,6 +211,12 @@ void nodangle(Design*des)
/*
* $Log: nodangle.cc,v $
* Revision 1.21.2.2 2006/08/23 04:08:55 steve
* Do not count self as signifincant in nodangle.
*
* Revision 1.21.2.1 2006/03/16 05:40:19 steve
* Fix crash when memory exploding doesnot work
*
* Revision 1.21 2004/02/20 18:53:35 steve
* Addtrbute keys are perm_strings.
*

82
parse.y
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: parse.y,v 1.201 2004/10/04 01:10:54 steve Exp $"
#ident "$Id: parse.y,v 1.201.2.4 2006/07/10 00:21:52 steve Exp $"
#endif
# include "config.h"
@ -287,7 +287,7 @@ attribute
}
| IDENTIFIER '=' expression
{ PExpr*tmp = $3;
if (!pform_expression_is_constant(tmp)) {
if (tmp && !pform_expression_is_constant(tmp)) {
yyerror(@3, "error: attribute value "
"expression must be constant.");
delete tmp;
@ -308,17 +308,14 @@ attribute
integers. This rule matches those declarations. The containing
rule has presumably set up the scope. */
block_item_decl
: attribute_list_opt K_reg signed_opt range register_variable_list ';'
{ pform_set_net_range($5, $4, $3);
if ($1) delete $1;
: K_reg signed_opt range register_variable_list ';'
{ pform_set_net_range($4, $3, $2);
}
| attribute_list_opt K_reg signed_opt register_variable_list ';'
{ pform_set_net_range($4, 0, $3);
if ($1) delete $1;
| K_reg signed_opt register_variable_list ';'
{ pform_set_net_range($3, 0, $2);
}
| attribute_list_opt K_integer register_variable_list ';'
{ pform_set_reg_integer($3);
if ($1) delete $1;
| K_integer register_variable_list ';'
{ pform_set_reg_integer($2);
}
| K_time register_variable_list ';'
{ pform_set_reg_time($2);
@ -335,15 +332,13 @@ block_item_decl
/* Recover from errors that happen within variable lists. Use the
trailing semi-colon to resync the parser. */
| attribute_list_opt K_reg error ';'
{ yyerror(@2, "error: syntax error in reg variable list.");
| K_reg error ';'
{ yyerror(@1, "error: syntax error in reg variable list.");
yyerrok;
if ($1) delete $1;
}
| attribute_list_opt K_integer error ';'
{ yyerror(@2, "error: syntax error in integer variable list.");
| K_integer error ';'
{ yyerror(@1, "error: syntax error in integer variable list.");
yyerrok;
if ($1) delete $1;
}
| K_time error ';'
{ yyerror(@1, "error: syntax error in time variable list.");
@ -981,6 +976,14 @@ expr_primary
{ PEConcat*tmp = new PEConcat(*$2);
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
for (unsigned idx = 0 ; idx < (*$2).count() ; idx += 1) {
PExpr*ex = (*$2)[idx];
if (ex == 0) {
yyerror(@1, "error: Null arguments not allowed"
" in repeat expressions.");
break;
}
}
delete $2;
$$ = tmp;
}
@ -990,7 +993,6 @@ expr_primary
yyerror(@2, "error: Repeat expression "
"must be constant.");
delete rep;
delete $2;
rep = 0;
}
PEConcat*tmp = new PEConcat(*$4, rep);
@ -2266,7 +2268,7 @@ specify_item
{
}
| K_Shold '(' spec_reference_event ',' spec_reference_event
',' expression spec_notifier_opt ')' ';'
',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
}
| K_Speriod '(' spec_reference_event ',' delay_value
@ -2274,11 +2276,11 @@ specify_item
{ delete $5;
}
| K_Srecovery '(' spec_reference_event ',' spec_reference_event
',' expression spec_notifier_opt ')' ';'
',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
}
| K_Ssetup '(' spec_reference_event ',' spec_reference_event
',' expression spec_notifier_opt ')' ';'
',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
}
| K_Ssetuphold '(' spec_reference_event ',' spec_reference_event
@ -2296,7 +2298,7 @@ specify_item
{ delete $5;
delete $7;
}
| K_Swidth '(' spec_reference_event ',' expression ')' ';'
| K_Swidth '(' spec_reference_event ',' delay_value ')' ';'
{ delete $5;
}
;
@ -2541,9 +2543,9 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| K_begin error K_end
/* | K_begin error K_end
{ yyerrok; }
*/
/* fork-join blocks are very similar to begin-end blocks. In fact,
from the parser's perspective there is no real difference. All we
need to do is remember that this is a parallel block so that the
@ -2690,28 +2692,34 @@ statement
tmp->set_lineno(@1.first_line);
$$ = tmp;
}
| event_control statement_opt
| event_control attribute_list_opt statement_opt
{ PEventStatement*tmp = $1;
if (tmp == 0) {
yyerror(@1, "error: Invalid event control.");
$$ = 0;
} else {
tmp->set_statement($2);
pform_attach_attributes($3, $2);
tmp->set_statement($3);
$$ = tmp;
}
if ($2) delete $2;
}
| '@' '*' statement_opt
| '@' '*' attribute_list_opt statement_opt
{ PEventStatement*tmp = new PEventStatement;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
tmp->set_statement($3);
pform_attach_attributes($4, $3);
tmp->set_statement($4);
if ($3) delete $3;
$$ = tmp;
}
| '@' '(' '*' ')' statement_opt
| '@' '(' '*' ')' attribute_list_opt statement_opt
{ PEventStatement*tmp = new PEventStatement;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
tmp->set_statement($5);
pform_attach_attributes($6, $5);
tmp->set_statement($6);
if ($5) delete $5;
$$ = tmp;
}
| lpvalue '=' expression ';'
@ -2820,14 +2828,18 @@ statement
;
statement_list
: statement_list statement
{ svector<Statement*>*tmp = new svector<Statement*>(*$1, $2);
: statement_list attribute_list_opt statement
{ pform_attach_attributes($3, $2);
svector<Statement*>*tmp = new svector<Statement*>(*$1, $3);
delete $1;
if ($2) delete $2;
$$ = tmp;
}
| statement
{ svector<Statement*>*tmp = new svector<Statement*>(1);
(*tmp)[0] = $1;
| attribute_list_opt statement
{ pform_attach_attributes($2, $1);
svector<Statement*>*tmp = new svector<Statement*>(1);
(*tmp)[0] = $2;
if ($1) delete $1;
$$ = tmp;
}
;

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: parse_api.h,v 1.3 2004/02/18 17:11:57 steve Exp $"
#ident "$Id: parse_api.h,v 1.3.2.1 2005/08/13 00:45:54 steve Exp $"
#endif
# include <stdio.h>
@ -35,8 +35,8 @@ class PUdp;
* Verilog source into pform for elaboration. The parser adds modules
* to these maps as it compiles modules in the verilog source.
*/
extern map<perm_string,Module*> pform_modules;
extern map<perm_string,PUdp*> pform_primitives;
extern std::map<perm_string,Module*> pform_modules;
extern std::map<perm_string,PUdp*> pform_primitives;
/*
* This code actually invokes the parser to make modules. The first
@ -47,10 +47,13 @@ extern map<perm_string,PUdp*> pform_primitives;
*/
extern int pform_parse(const char*path, FILE*file =0);
extern string vl_file;
extern std::string vl_file;
/*
* $Log: parse_api.h,v $
* Revision 1.3.2.1 2005/08/13 00:45:54 steve
* Fix compilation warnings/errors with newer compilers.
*
* Revision 1.3 2004/02/18 17:11:57 steve
* Use perm_strings for named langiage items.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: pform.cc,v 1.129 2004/10/04 01:10:55 steve Exp $"
#ident "$Id: pform.cc,v 1.129.2.1 2006/07/10 00:21:53 steve Exp $"
#endif
# include "config.h"
@ -203,6 +203,19 @@ verinum* pform_verinum_with_size(verinum*siz, verinum*val,
return res;
}
void pform_attach_attributes(Statement*obj, svector<named_pexpr_t*>*attr)
{
if (obj == 0)
return;
if (attr == 0)
return;
for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) {
named_pexpr_t*tmp = (*attr)[idx];
obj->attributes[tmp->name] = tmp->parm;
}
}
void pform_startmodule(const char*name, const char*file, unsigned lineno,
svector<named_pexpr_t*>*attr)
{
@ -1597,6 +1610,9 @@ int pform_parse(const char*path, FILE*file)
/*
* $Log: pform.cc,v $
* Revision 1.129.2.1 2006/07/10 00:21:53 steve
* Add support for full_case attribute.
*
* Revision 1.129 2004/10/04 01:10:55 steve
* Clean up spurious trailing white space.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: pform.h,v 1.81 2004/08/26 04:02:04 steve Exp $"
#ident "$Id: pform.h,v 1.81.2.1 2006/07/10 00:21:53 steve Exp $"
#endif
# include "netlist.h"
@ -219,6 +219,8 @@ extern void pform_set_attrib(perm_string name, perm_string key,
extern void pform_set_type_attrib(perm_string name, const string&key,
char*value);
extern void pform_attach_attributes(Statement*obj, svector<named_pexpr_t*>*attr);
extern void pform_set_parameter(perm_string name,
bool signed_flag,
svector<PExpr*>*range,
@ -298,6 +300,9 @@ extern void pform_dump(ostream&out, Module*mod);
/*
* $Log: pform.h,v $
* Revision 1.81.2.1 2006/07/10 00:21:53 steve
* Add support for full_case attribute.
*
* Revision 1.81 2004/08/26 04:02:04 steve
* Add support for localparam ranges.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: pform_dump.cc,v 1.88 2004/10/04 01:10:55 steve Exp $"
#ident "$Id: pform_dump.cc,v 1.88.2.1 2006/07/10 00:21:54 steve Exp $"
#endif
# include "config.h"
@ -418,6 +418,19 @@ void Statement::dump(ostream&out, unsigned ind) const
out << setw(ind) << "";
out << "/* " << get_line() << ": " << typeid(*this).name()
<< " */ ;" << endl;
dump_attributes(out, ind+2);
}
void Statement::dump_attributes(ostream&out, unsigned ind) const
{
for (map<perm_string,PExpr*>::const_iterator idx = attributes.begin()
; idx != attributes.end()
; idx ++) {
out << setw(ind) << "" << "(* " << (*idx).first;
if ((*idx).second)
out << " = " << *(*idx).second;
out << " *)" << endl;
}
}
void PAssign::dump(ostream&out, unsigned ind) const
@ -487,6 +500,8 @@ void PCase::dump(ostream&out, unsigned ind) const
}
out << " (" << *expr_ << ") /* " << get_line() << " */" << endl;
dump_attributes(out, ind+2);
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
PCase::Item*cur = (*items_)[idx];
@ -909,6 +924,9 @@ void PUdp::dump(ostream&out) const
/*
* $Log: pform_dump.cc,v $
* Revision 1.88.2.1 2006/07/10 00:21:54 steve
* Add support for full_case attribute.
*
* Revision 1.88 2004/10/04 01:10:55 steve
* Clean up spurious trailing white space.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: set_width.cc,v 1.34 2003/08/28 04:11:19 steve Exp $"
#ident "$Id: set_width.cc,v 1.34.2.1 2005/03/05 01:36:16 steve Exp $"
#endif
# include "config.h"
@ -167,12 +167,13 @@ bool NetEBDiv::set_width(unsigned w)
return w == expr_width();
}
/*
* The logical binary operators do not care what the widths of their
* operands are, the output is always 1 bit. The operands are
* self-determined, so a set_width is stopped here.
*/
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);
}
@ -411,6 +412,9 @@ bool NetEUReduce::set_width(unsigned w)
/*
* $Log: set_width.cc,v $
* Revision 1.34.2.1 2005/03/05 01:36:16 steve
* Fix set_width to allow binary logical operands to be self determined.
*
* Revision 1.34 2003/08/28 04:11:19 steve
* Spelling patch.
*

View File

@ -1,7 +1,7 @@
PKG="IVLver"
NAME="verilog"
ARCH="sparc"
VERSION="0.7"
VERSION="0.8"
CATEGORY="application"
VENDOR="Icarus.com"
EMAIL="steve@icarus.com"

View File

@ -4,6 +4,7 @@ f none bin/iverilog 0755 bin bin
f none bin/iverilog-vpi 0755 bin bin
f none bin/vvp 0755 bin bin
d none include 0755 bin bin
f none include/_pli_types.h 0644 bin bin
f none include/acc_user.h 0644 bin bin
f none include/ivl_target.h 0644 bin bin
f none include/veriuser.h 0644 bin bin
@ -11,12 +12,21 @@ f none include/vpi_user.h 0644 bin bin
d none lib 0755 bin bin
d none lib/ivl 0755 bin bin
f none lib/ivl/fpga.tgt 0644 bin bin
f none lib/ivl/fpga.conf 0644 bin bin
f none lib/ivl/fpga-s.conf 0644 bin bin
f none lib/ivl/iverilog.conf 0644 bin bin
f none lib/ivl/ivl 0755 bin bin
f none lib/ivl/ivlpp 0755 bin bin
f none lib/ivl/null.tgt 0644 bin bin
f none lib/ivl/null.conf 0644 bin bin
f none lib/ivl/null-s.conf 0644 bin bin
f none lib/ivl/system.vpi 0644 bin bin
f none lib/ivl/system.sft 0644 bin bin
f none lib/ivl/vvp.tgt 0644 bin bin
f none lib/ivl/vvp.conf 0644 bin bin
f none lib/ivl/vvp-s.conf 0644 bin bin
f none lib/ivl/xnf.conf 0644 bin bin
f none lib/ivl/xnf-s.conf 0644 bin bin
f none lib/libveriuser.a 0644 bin bin
f none lib/libvpi.a 0644 bin bin
d none man 0755 bin bin

View File

@ -21,7 +21,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: svector.h,v 1.9 2003/07/23 02:35:44 steve Exp $"
#ident "$Id: svector.h,v 1.9.2.1 2005/06/14 15:33:54 steve Exp $"
#endif
# include "config.h"
@ -101,14 +101,17 @@ template <class TYPE> class svector {
* Override the implementation of the above template for the string
* type parameter. The initialization to nil works different here.
*/
inline svector<string>::svector<string>(unsigned size)
: nitems_(size), items_(new string[size])
template <> inline svector<std::string>::svector(unsigned size)
: nitems_(size), items_(new std::string[size])
{
}
/*
* $Log: svector.h,v $
* Revision 1.9.2.1 2005/06/14 15:33:54 steve
* Fix gcc4 build issues.
*
* Revision 1.9 2003/07/23 02:35:44 steve
* Inline the svector<string> constructor.
*

2159
synth2.cc

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll-api.cc,v 1.108 2004/10/04 01:10:55 steve Exp $"
#ident "$Id: t-dll-api.cc,v 1.108.2.5 2006/04/16 19:26:40 steve Exp $"
#endif
# include "config.h"
@ -620,6 +620,19 @@ extern "C" const char* ivl_udp_name(ivl_udp_t net)
return net->name;
}
extern "C" unsigned ivl_lpm_attr_cnt(ivl_lpm_t net)
{
return net->nattr;
}
extern "C" ivl_attribute_t ivl_lpm_attr_val(ivl_lpm_t net, unsigned idx)
{
if (idx >= net->nattr)
return 0;
else
return net->attr + idx;
}
extern "C" const char* ivl_lpm_basename(ivl_lpm_t net)
{
return net->name;
@ -752,6 +765,10 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
assert(idx < net->u_.arith.width);
return net->u_.arith.a[idx];
case IVL_LPM_DEMUX:
assert(idx < net->u_.demux.width);
return net->u_.demux.d[idx];
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
assert(idx < net->u_.shift.width);
@ -788,6 +805,10 @@ extern "C" ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx)
assert(idx < net->u_.arith.width);
return net->u_.arith.b[idx];
case IVL_LPM_DEMUX:
assert(idx < net->u_.demux.width/net->u_.demux.size);
return net->u_.demux.bit_in[idx];
default:
assert(0);
return 0;
@ -813,6 +834,22 @@ extern "C" ivl_nexus_t ivl_lpm_data2(ivl_lpm_t net, unsigned sdx, unsigned idx)
return net->u_.ufunc.pins[base+idx];
}
case IVL_LPM_RAM:
if (net->u_.ff.a.mem == 0) {
// This is an exploded RAM, so we use sdx and idx
// to address a nexa into the exploded ram.
if (sdx >= net->u_.ff.scnt)
return 0;
if (idx >= net->u_.ff.width)
return 0;
unsigned adr = sdx * net->u_.ff.width + idx;
return net->u_.ff.d.pins[adr];
} else {
// Normal RAM port does not have data2 nexa
return 0;
}
default:
assert(0);
return 0;
@ -833,6 +870,18 @@ extern "C" unsigned ivl_lpm_data2_width(ivl_lpm_t net, unsigned sdx)
}
}
extern "C" ivl_lpm_t ivl_lpm_decode(ivl_lpm_t net)
{
assert(net);
switch (net->type) {
case IVL_LPM_FF:
return net->u_.ff.a.decode;
default:
assert(0);
return 0;
}
}
/*
* This function returns the hierarchical name for the LPM device. The
* name needs to be built up from the scope name and the lpm base
@ -898,6 +947,10 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
else
return net->u_.mux.q.pins[idx];
case IVL_LPM_DEMUX:
assert(idx < net->u_.demux.width);
return net->u_.demux.q[idx];
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
assert(idx < net->u_.shift.width);
@ -929,6 +982,7 @@ extern "C" ivl_nexus_t ivl_lpm_select(ivl_lpm_t net, unsigned idx)
else
return net->u_.ff.s.pins[idx];
case IVL_LPM_DECODE:
case IVL_LPM_MUX:
assert(idx < net->u_.mux.swid);
if (net->u_.mux.swid == 1)
@ -936,6 +990,10 @@ extern "C" ivl_nexus_t ivl_lpm_select(ivl_lpm_t net, unsigned idx)
else
return net->u_.mux.s.pins[idx];
case IVL_LPM_DEMUX:
assert(idx < net->u_.demux.awid);
return net->u_.demux.a[idx];
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
assert(idx < net->u_.shift.select);
@ -952,8 +1010,11 @@ extern "C" unsigned ivl_lpm_selects(ivl_lpm_t net)
switch (net->type) {
case IVL_LPM_RAM:
return net->u_.ff.swid;
case IVL_LPM_DECODE:
case IVL_LPM_MUX:
return net->u_.mux.swid;
case IVL_LPM_DEMUX:
return net->u_.demux.awid;
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
return net->u_.shift.select;
@ -970,6 +1031,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
case IVL_LPM_FF:
case IVL_LPM_RAM:
case IVL_LPM_MUX:
case IVL_LPM_DEMUX:
return 0;
case IVL_LPM_ADD:
case IVL_LPM_CMP_EQ:
@ -984,7 +1046,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
return net->u_.shift.signed_flag;
return 0;
case IVL_LPM_DECODE:
case IVL_LPM_UFUNC:
return 0;
default:
@ -996,8 +1058,12 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
extern "C" unsigned ivl_lpm_size(ivl_lpm_t net)
{
switch (net->type) {
case IVL_LPM_DEMUX:
return net->u_.demux.size;
case IVL_LPM_MUX:
return net->u_.mux.size;
case IVL_LPM_RAM:
return net->u_.ff.scnt;
case IVL_LPM_UFUNC:
return net->u_.ufunc.ports - 1;
default:
@ -1018,8 +1084,11 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net)
case IVL_LPM_FF:
case IVL_LPM_RAM:
return net->u_.ff.width;
case IVL_LPM_DECODE:
case IVL_LPM_MUX:
return net->u_.mux.width;
case IVL_LPM_DEMUX:
return net->u_.demux.width;
case IVL_LPM_ADD:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_GE:
@ -1046,7 +1115,7 @@ extern "C" ivl_memory_t ivl_lpm_memory(ivl_lpm_t net)
assert(net);
switch (net->type) {
case IVL_LPM_RAM:
return net->u_.ff.mem;
return net->u_.ff.a.mem;
default:
assert(0);
return 0;
@ -1935,6 +2004,21 @@ extern "C" ivl_variable_type_t ivl_variable_type(ivl_variable_t net)
/*
* $Log: t-dll-api.cc,v $
* Revision 1.108.2.5 2006/04/16 19:26:40 steve
* Fix handling of exploded memories with partial or missing resets.
*
* Revision 1.108.2.4 2006/03/26 23:09:24 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.108.2.3 2006/03/12 07:34:19 steve
* Fix the memsynth1 case.
*
* Revision 1.108.2.2 2006/02/25 05:03:29 steve
* Add support for negedge FFs by using attributes.
*
* Revision 1.108.2.1 2006/02/19 00:11:33 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.108 2004/10/04 01:10:55 steve
* Clean up spurious trailing white space.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll-expr.cc,v 1.39 2004/06/17 16:06:19 steve Exp $"
#ident "$Id: t-dll-expr.cc,v 1.39.2.2 2006/09/15 23:56:05 steve Exp $"
#endif
# include "config.h"
@ -222,12 +222,73 @@ void dll_target::expr_memory(const NetEMemory*net)
ivl_expr_t cur = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
assert(cur);
cur->type_ = IVL_EX_MEMORY;
cur->value_ = IVL_VT_VECTOR;
cur->width_= net->expr_width();
cur->signed_ = net->has_sign()? 1 : 0;
cur->u_.memory_.mem_ = find_memory(des_, net->memory());
cur->u_.memory_.idx_ = expr_;
const NetMemory*mem = net->memory();
if (const NetNet*reg = mem->reg_from_explode()) {
if (expr_ == 0) {
// If there is no index expression for the
// exploded memory, then replace it with the
// entire exploded reg.
cur->type_ = IVL_EX_SIGNAL;
cur->value_ = IVL_VT_VECTOR;
cur->width_= reg->pin_count();
cur->signed_ = net->has_sign()? 1 : 0;
cur->u_.signal_.sig = find_signal(des_, reg);
cur->u_.signal_.lsi = 0;
cur->u_.signal_.msi = cur->width_ - 1;
} else {
cur->type_ = IVL_EX_SELECT;
cur->value_ = IVL_VT_VECTOR;
cur->width_ = net->expr_width();
cur->signed_ = net->has_sign()? 1 : 0;
// Create an expression form of the exploded
// memory. This is what the select will apply to.
ivl_expr_t sig = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s));
sig->type_ = IVL_EX_SIGNAL;
sig->value_ = IVL_VT_VECTOR;
sig->width_ = reg->pin_count();
sig->signed_ = 0;
sig->u_.signal_.sig = find_signal(des_, reg);
assert(sig->u_.signal_.sig);
sig->u_.signal_.lsi = 0;
sig->u_.signal_.msi = reg->pin_count()-1;
cur->u_.binary_.lef_ = sig;
// Create an expression of the address calculation.
cur->u_.binary_.rig_ = expr_;
if (cur->width_ > 1) {
ivl_expr_t mul = (ivl_expr_t)calloc(2, sizeof(struct ivl_expr_s));
ivl_expr_t fac = mul+1;
fac->type_ = IVL_EX_ULONG;
fac->value_ = IVL_VT_VECTOR;
fac->width_ = 8*sizeof(cur->width_);
fac->signed_= 0;
fac->u_.ulong_.value = cur->width_;
mul->type_ = IVL_EX_BINARY;
mul->value_ = IVL_VT_VECTOR;
mul->width_ = fac->width_;
mul->signed_= 0;
mul->u_.binary_.op_ = '*';
mul->u_.binary_.lef_ = cur->u_.binary_.rig_;
mul->u_.binary_.rig_ = fac;
cur->u_.binary_.rig_ = mul;
}
}
} else {
cur->type_ = IVL_EX_MEMORY;
cur->value_ = IVL_VT_VECTOR;
cur->width_= net->expr_width();
cur->signed_ = net->has_sign()? 1 : 0;
cur->u_.memory_.mem_ = find_memory(des_, net->memory());
cur->u_.memory_.idx_ = expr_;
}
expr_ = cur;
}
@ -604,6 +665,12 @@ void dll_target::expr_variable(const NetEVariable*net)
/*
* $Log: t-dll-expr.cc,v $
* Revision 1.39.2.2 2006/09/15 23:56:05 steve
* Special handling of exploded memory arguments.
*
* Revision 1.39.2.1 2006/03/12 07:34:19 steve
* Fix the memsynth1 case.
*
* Revision 1.39 2004/06/17 16:06:19 steve
* Help system function signedness survive elaboration.
*

220
t-dll.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll.cc,v 1.131 2004/10/04 01:10:55 steve Exp $"
#ident "$Id: t-dll.cc,v 1.131.2.8 2006/07/23 19:42:35 steve Exp $"
#endif
# include "config.h"
@ -940,6 +940,8 @@ void dll_target::net_case_cmp(const NetCaseCmp*net)
obj->delay[1] = net->fall_time();
obj->delay[2] = net->decay_time();
logic_attributes(obj,net);
scope_add_logic(scope, obj);
}
@ -965,6 +967,8 @@ bool dll_target::net_function(const NetUserFunc*net)
obj->type = IVL_LPM_UFUNC;
obj->name = net->name();
obj->scope = find_scope(des_, net->scope());
obj->attr = 0;
obj->nattr = 0;
assert(obj->scope);
/* Get the definition of the function and save it. */
@ -1104,9 +1108,11 @@ void dll_target::lpm_add_sub(const NetAddSub*net)
obj->type = IVL_LPM_SUB;
else
obj->type = IVL_LPM_ADD;
obj->name = net->name(); // NetAddSub names are permallocated.
obj->name = net->name(); // NetAddSub names are permallocated
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
obj->attr = 0;
obj->nattr = 0;
assert(obj->scope);
obj->u_.arith.signed_flag = 0;
@ -1176,6 +1182,8 @@ void dll_target::lpm_clshift(const NetCLShift*net)
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_SHIFTL;
obj->name = net->name();
obj->attr = 0;
obj->nattr = 0;
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
@ -1243,6 +1251,8 @@ void dll_target::lpm_clshift(const NetCLShift*net)
void dll_target::lpm_compare(const NetCompare*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->attr = 0;
obj->nattr = 0;
obj->name = net->name(); // NetCompare names are permallocated
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
@ -1357,6 +1367,8 @@ void dll_target::lpm_divide(const NetDivide*net)
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_DIVIDE;
obj->name = net->name();
obj->attr = 0;
obj->nattr = 0;
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
@ -1427,6 +1439,8 @@ void dll_target::lpm_modulo(const NetModulo*net)
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_MOD;
obj->name = net->name();
obj->attr = 0;
obj->nattr = 0;
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
@ -1489,16 +1503,131 @@ void dll_target::lpm_modulo(const NetModulo*net)
scope_add_lpm(obj->scope, obj);
}
bool dll_target::lpm_decode(const NetDecode*net)
{
return true;
}
ivl_lpm_t dll_target::lpm_decode_ff_(const NetDecode*net)
{
if (net == 0)
return 0;
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_DECODE;
obj->name = net->name();
obj->attr = 0;
obj->nattr = 0;
obj->scope = find_scope(des_, net->scope());
obj->u_.mux.swid = net->awidth();
obj->u_.mux.size = 0;
obj->u_.mux.width = net->width();
obj->u_.mux.d = 0;
if (obj->u_.mux.swid > 1) {
obj->u_.mux.s.pins = new ivl_nexus_t[obj->u_.mux.swid];
for (unsigned idx = 0 ; idx < obj->u_.mux.swid ; idx += 1) {
const Nexus*nex = net->pin_Address(idx).nexus();
assert(nex->t_cookie());
obj->u_.mux.s.pins[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.mux.s.pins[idx], obj, idx,
IVL_DR_HiZ, IVL_DR_HiZ);
}
} else {
assert(obj->u_.mux.swid == 1);
const Nexus*nex = net->pin_Address(0).nexus();
assert(nex->t_cookie());
obj->u_.mux.s.pin = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.mux.s.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
}
scope_add_lpm(obj->scope, obj);
return obj;
}
bool dll_target::lpm_demux(const NetDemux*net)
{
unsigned idx;
unsigned width = net->width();
unsigned awid = net->awidth();
unsigned size = net->size();
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_DEMUX;
obj->name = net->name();
obj->attr = 0;
obj->nattr = 0;
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
obj->u_.demux.width = width;
obj->u_.demux.awid = awid;
obj->u_.demux.size = net->size();
ivl_nexus_t*tmp = new ivl_nexus_t [2*width + awid + width/size];
obj->u_.demux.q = tmp;
obj->u_.demux.d = tmp + width;
obj->u_.demux.a = tmp + 2*width;
obj->u_.demux.bit_in = tmp + 2*width + awid;
for (idx = 0 ; idx < width ; idx += 1) {
const Nexus*nex = net->pin_Q(idx).nexus();
obj->u_.demux.q[idx] = (ivl_nexus_t) nex->t_cookie();
/* It is possible, but unlikely, that the Q is unused. */
if (obj->u_.demux.q[idx])
nexus_lpm_add(obj->u_.demux.q[idx], obj, idx,
IVL_DR_STRONG, IVL_DR_STRONG);
}
for (idx = 0 ; idx < width ; idx += 1) {
const Nexus*nex = net->pin_Data(idx).nexus();
assert(nex->t_cookie());
obj->u_.demux.d[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.demux.d[idx], obj, idx,
IVL_DR_HiZ, IVL_DR_HiZ);
}
for (idx = 0 ; idx < awid ; idx += 1) {
const Nexus*nex = net->pin_Address(idx).nexus();
assert(nex->t_cookie());
obj->u_.demux.a[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.demux.a[idx], obj, idx,
IVL_DR_HiZ, IVL_DR_HiZ);
}
for (idx = 0 ; idx < width/size ; idx += 1) {
const Nexus*nex = net->pin_WriteData(idx).nexus();
assert(nex->t_cookie());
obj->u_.demux.bit_in[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.demux.bit_in[idx], obj, 0,
IVL_DR_HiZ, IVL_DR_HiZ);
}
obj->nattr = net->attr_cnt();
obj->attr = fill_in_attributes(net);
scope_add_lpm(obj->scope, obj);
return true;
}
void dll_target::lpm_ff(const NetFF*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_FF;
obj->name = net->name();
obj->attr = 0;
obj->nattr = 0;
obj->scope = find_scope(des_, net->scope());
obj->u_.ff.a.decode = lpm_decode_ff_(net->get_demux());
assert(obj->scope);
obj->u_.ff.width = net->width();
obj->nattr = net->attr_cnt();
obj->attr = fill_in_attributes(net);
scope_add_lpm(obj->scope, obj);
const Nexus*nex;
@ -1607,16 +1736,23 @@ void dll_target::lpm_ff(const NetFF*net)
void dll_target::lpm_ram_dq(const NetRamDq*net)
{
ivl_memory_t mem = find_memory(des_, net->mem());
assert(mem);
const NetNet*ereg = net->mem()->reg_from_explode();
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_RAM;
obj->name = net->name();
obj->u_.ff.mem = find_memory(des_, net->mem());
assert(obj->u_.ff.mem);
obj->attr = 0;
obj->nattr = 0;
obj->u_.ff.a.mem = ereg? 0 : mem;
obj->scope = find_scope(des_, net->mem()->scope());
assert(obj->scope);
obj->u_.ff.width = net->width();
obj->u_.ff.swid = net->awidth();
obj->u_.ff.scnt = net->mem()->count();
scope_add_lpm(obj->scope, obj);
@ -1626,6 +1762,7 @@ void dll_target::lpm_ram_dq(const NetRamDq*net)
// the clock input.
bool has_write_port = net->pin_InClock().is_linked();
assert( ereg? !has_write_port : 1 );
// Connect the write clock and write enable
@ -1717,6 +1854,21 @@ void dll_target::lpm_ram_dq(const NetRamDq*net)
IVL_DR_STRONG, IVL_DR_STRONG);
}
}
if (ereg) {
unsigned count = obj->u_.ff.width * obj->u_.ff.scnt;
assert(ereg->pin_count() == count);
obj->u_.ff.d.pins = new ivl_nexus_t [count];
for (unsigned idx = 0 ; idx < count ; idx += 1) {
nex = ereg->pin(idx).nexus();
assert(nex->t_cookie());
obj->u_.ff.d.pins[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.ff.d.pins[idx], obj, 0,
IVL_DR_HiZ, IVL_DR_HiZ);
}
}
}
void dll_target::lpm_mult(const NetMult*net)
@ -1724,6 +1876,8 @@ void dll_target::lpm_mult(const NetMult*net)
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_MULT;
obj->name = net->name();
obj->attr = 0;
obj->nattr = 0;
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
@ -1803,7 +1957,9 @@ void dll_target::lpm_mux(const NetMux*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_MUX;
obj->name = net->name(); // The NetMux perallocates its name.
obj->name = net->name(); // NetMux names are permallocated
obj->attr = 0;
obj->nattr = 0;
obj->scope = find_scope(des_, net->scope());
assert(obj->scope);
@ -1828,10 +1984,34 @@ void dll_target::lpm_mux(const NetMux*net)
for (unsigned idx = 0 ; idx < obj->u_.mux.width ; idx += 1) {
nex = net->pin_Result(idx).nexus();
assert(nex->t_cookie());
#if 0
if (! nex->t_cookie()) {
cerr << net->get_line() << ": internal error: "
<< "broken mux. name=" << net->name()
<< ", width=" << obj->u_.mux.width
<< ", swid=" << obj->u_.mux.swid << endl;
for (unsigned tmp = 0; tmp < obj->u_.mux.width; tmp += 1) {
const Nexus*tmpn = net->pin_Result(tmp).nexus();
if (tmpn->t_cookie() == 0)
continue;
cerr << net->get_line() << ": XXXX "
<< "Result(" << tmp << ") : "
<< tmpn->name() << endl;
}
}
#endif
obj->u_.mux.q.pins[idx] = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.mux.q.pins[idx], obj, 0,
IVL_DR_STRONG, IVL_DR_STRONG);
/* It is possible (although unlikely) that the
result bit of the mux is not used. This can
happen, for example, if the output is
overridden in the HDL. In that case, skip
it. But if the bit is used, then add it to the
nexus. */
if (obj->u_.mux.q.pins[idx])
nexus_lpm_add(obj->u_.mux.q.pins[idx], obj, 0,
IVL_DR_STRONG, IVL_DR_STRONG);
}
}
@ -2180,6 +2360,30 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj };
/*
* $Log: t-dll.cc,v $
* Revision 1.131.2.8 2006/07/23 19:42:35 steve
* Handle statement output override better in blocks.
*
* Revision 1.131.2.7 2006/04/16 19:26:40 steve
* Fix handling of exploded memories with partial or missing resets.
*
* Revision 1.131.2.6 2006/03/26 23:09:24 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.131.2.5 2006/03/12 07:34:19 steve
* Fix the memsynth1 case.
*
* Revision 1.131.2.4 2006/02/25 05:03:29 steve
* Add support for negedge FFs by using attributes.
*
* Revision 1.131.2.3 2006/02/19 00:11:34 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.131.2.2 2006/01/21 21:42:33 steve
* When mux has wide select but sparse choices, use 1hot translation.
*
* Revision 1.131.2.1 2005/02/19 16:39:31 steve
* Spellig fixes.
*
* Revision 1.131 2004/10/04 01:10:55 steve
* Clean up spurious trailing white space.
*

38
t-dll.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll.h,v 1.115 2004/10/04 01:10:56 steve Exp $"
#ident "$Id: t-dll.h,v 1.115.2.5 2006/04/16 19:26:40 steve Exp $"
#endif
# include "target.h"
@ -76,6 +76,8 @@ struct dll_target : public target_t, public expr_scan_t {
void lpm_add_sub(const NetAddSub*);
void lpm_clshift(const NetCLShift*);
void lpm_compare(const NetCompare*);
bool lpm_decode(const NetDecode*);
bool lpm_demux(const NetDemux*);
void lpm_divide(const NetDivide*);
void lpm_ff(const NetFF*);
void lpm_modulo(const NetModulo*);
@ -162,6 +164,8 @@ struct dll_target : public target_t, public expr_scan_t {
void add_root(ivl_design_s &des_, const NetScope *s);
ivl_lpm_t lpm_decode_ff_(const NetDecode*);
void sub_off_from_expr_(long);
void mul_expr_by_const_(long);
@ -290,10 +294,14 @@ struct ivl_lpm_s {
ivl_scope_t scope;
perm_string name;
struct ivl_attribute_s*attr;
unsigned nattr;
union {
struct ivl_lpm_ff_s {
unsigned width;
unsigned swid; // ram only
unsigned scnt;
ivl_nexus_t clk;
ivl_nexus_t we;
ivl_nexus_t aclr;
@ -312,7 +320,10 @@ struct ivl_lpm_s {
ivl_nexus_t*pins;
ivl_nexus_t pin;
} s;
ivl_memory_t mem; // ram only
union {
ivl_memory_t mem; // ram only
ivl_lpm_t decode; // FF only
} a;
ivl_expr_t aset_value;
ivl_expr_t sset_value;
} ff;
@ -332,6 +343,14 @@ struct ivl_lpm_s {
} s;
} mux;
struct ivl_lpm_demux_s {
unsigned width;
unsigned awid;
unsigned size;
ivl_nexus_t*bit_in;
ivl_nexus_t *q,*d,*a;
} demux;
struct ivl_lpm_shift_s {
unsigned width;
unsigned select;
@ -684,6 +703,21 @@ struct ivl_variable_s {
/*
* $Log: t-dll.h,v $
* Revision 1.115.2.5 2006/04/16 19:26:40 steve
* Fix handling of exploded memories with partial or missing resets.
*
* Revision 1.115.2.4 2006/03/26 23:09:25 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.115.2.3 2006/03/12 07:34:19 steve
* Fix the memsynth1 case.
*
* Revision 1.115.2.2 2006/02/25 05:03:30 steve
* Add support for negedge FFs by using attributes.
*
* Revision 1.115.2.1 2006/02/19 00:11:34 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.115 2004/10/04 01:10:56 steve
* Clean up spurious trailing white space.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: target.cc,v 1.69 2004/05/31 23:34:39 steve Exp $"
#ident "$Id: target.cc,v 1.69.2.2 2006/03/26 23:09:25 steve Exp $"
#endif
# include "config.h"
@ -101,6 +101,20 @@ void target_t::lpm_compare(const NetCompare*)
"Unhandled NetCompare." << endl;
}
bool target_t::lpm_decode(const NetDecode*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetDecode." << endl;
return false;
}
bool target_t::lpm_demux(const NetDemux*)
{
cerr << "target (" << typeid(*this).name() << "): "
"Unhandled NetDemux." << endl;
return false;
}
void target_t::lpm_divide(const NetDivide*)
{
cerr << "target (" << typeid(*this).name() << "): "
@ -420,6 +434,12 @@ void expr_scan_t::expr_binary(const NetEBinary*ex)
/*
* $Log: target.cc,v $
* Revision 1.69.2.2 2006/03/26 23:09:25 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.69.2.1 2006/02/19 00:11:34 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.69 2004/05/31 23:34:39 steve
* Rewire/generalize parsing an elaboration of
* function return values to allow for better

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: target.h,v 1.65 2004/05/31 23:34:39 steve Exp $"
#ident "$Id: target.h,v 1.65.2.2 2006/03/26 23:09:25 steve Exp $"
#endif
# include "netlist.h"
@ -79,6 +79,8 @@ struct target_t {
virtual void lpm_add_sub(const NetAddSub*);
virtual void lpm_clshift(const NetCLShift*);
virtual void lpm_compare(const NetCompare*);
virtual bool lpm_decode(const NetDecode*);
virtual bool lpm_demux(const NetDemux*);
virtual void lpm_divide(const NetDivide*);
virtual void lpm_modulo(const NetModulo*);
virtual void lpm_ff(const NetFF*);
@ -170,6 +172,12 @@ extern const struct target *target_table[];
/*
* $Log: target.h,v $
* Revision 1.65.2.2 2006/03/26 23:09:25 steve
* Handle asynchronous demux/bit replacements.
*
* Revision 1.65.2.1 2006/02/19 00:11:34 steve
* Handle synthesis of FF vectors with l-value decoder.
*
* Revision 1.65 2004/05/31 23:34:39 steve
* Rewire/generalize parsing an elaboration of
* function return values to allow for better

6
tgt-edif/.cvsignore Normal file
View File

@ -0,0 +1,6 @@
configure
Makefile
edif.tgt
dep
config.status
config.log

46
tgt-edif/LICENSE.txt Normal file
View File

@ -0,0 +1,46 @@
The tgt-edif files are licensed differently from the rest of Icarus
Verilog. These files are:
--
Copyright (c) 2005 Stephen Williams
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
The purpose of the different license here is to allow licensees to use
these files to make EDIF based code generators that use these common
functions without statically linking to GPL files from elsewhere
within Icarus Verilog.
As a reminder, while this more relaxed license is here to allow
entities to make closed source (binary) code generators, this is not
intended to effect the GPL standing of the rest of Icarus Verilog
source. THIS RELAXED LICENSE APPLIES ONLY TO FILES SPECIFICALLY MARKED
WITH THIS NEW LICENSE. Furthermore, all rights remain reserved. Note
specifically the requirement for you to reproduce notices in your
documentation.

148
tgt-edif/Makefile.in Normal file
View File

@ -0,0 +1,148 @@
#
# Copyright (c) 2005 Stephen Williams
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#ident "$Id: Makefile.in,v 1.1.2.3 2006/05/08 04:33:36 steve Exp $"
#
#
SHELL = /bin/sh
VERSION = 0.0
prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
mandir = @mandir@
VPATH = $(srcdir)
bindir = @bindir@
libdir = @libdir@
includedir = $(prefix)/include
CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
RANLIB = @RANLIB@
MAN = @MAN@
PS2pdf = @ps2pdf@
CPPFLAGS = @ident_support@ -I.. -I$(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@
CFLAGS = -Wall @CFLAGS@
LDFLAGS = @LDFLAGS@
all: dep edif.tgt
dep:
mkdir dep
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
D = d-lpm.o d-virtex.o xilinx.o
O = edif.o device.o target.o gates.o generic.o $D
ifeq (@WIN32@,yes)
TGTLDFLAGS=-L.. -livl
TGTDEPLIBS=../libivl.a
else
TGTLDFLAGS=
TGTDEPLIBS=
endif
edif.tgt: tables.o libedif_tgt.a $(TGTDEPLIBS)
$(CC) @shared@ -o $@ tables.o libedif_tgt.a $(TGTLDFLAGS)
libedif_tgt.a: $O
rm -f libedif_tgt.a
ar cqv libedif_tgt.a $O
$(RANLIB) libedif_tgt.a
iverilog-edif.ps: $(srcdir)/iverilog-edif.man
$(MAN) -t $(srcdir)/iverilog-edif.man > iverilog-edif.ps
iverilog-edif.pdf: iverilog-edif.ps
$(PS2PDF) iverilog-edif.ps iverilog-edif.pdf
Makefile: Makefile.in config.status
./config.status
clean:
rm -rf *.o dep edif.tgt
distclean: clean
rm -f Makefile config.status config.log config.cache
rm -rf autom4te.cache
check: all
ifeq (@WIN32@,yes)
ifeq ($(MAN),none)
INSTALL_DOC =
else
ifeq ($(PS2PDF),none)
#INSTALL_DOC = $(mandir)/man1/iverilog-edif.1
else
#INSTALL_DOC = $(prefix)/iverilog-edif.pdf $(mandir)/man1/iverilog-edif.1
#all: iverilog-edif.pdf
endif
endif
else
#INSTALL_DOC = $(prefix)/iverilog-edif.pdf $(mandir)/man1/iverilog-edif.1
#INSTALL_DOCDIR = $(mandir)/man1
endif
install: all installdirs $(libdir)/ivl/edif.tgt $(INSTALL_DOC) $(libdir)/ivl/edif.conf $(libdir)/ivl/edif-s.conf
$(libdir)/ivl/edif.tgt: ./edif.tgt
$(INSTALL_PROGRAM) ./edif.tgt $(libdir)/ivl/edif.tgt
$(libdir)/ivl/edif.conf: $(srcdir)/edif.conf
$(INSTALL_DATA) $(srcdir)/edif.conf $(libdir)/ivl/edif.conf
$(libdir)/ivl/edif-s.conf: $(srcdir)/edif-s.conf
$(INSTALL_DATA) $(srcdir)/edif-s.conf $(libdir)/ivl/edif-s.conf
$(mandir)/man1/iverilog-edif.1: $(srcdir)/iverilog-edif.man
$(INSTALL_DATA) $(srcdir)/iverilog-edif.man $(mandir)/man1/iverilog-edif.1
$(prefix)/iverilog-edif.pdf: iverilog-edif.pdf
$(INSTALL_DATA) iverilog-edif.pdf $(prefix)/iverilog-edif.pdf
installdirs: ../mkinstalldirs
$(srcdir)/../mkinstalldirs $(libdir)/ivl
uninstall:
rm -f $(libdir)/ivl/edif.tgt
rm -f $(INSTALL_DOC)
rm -f $(libdir)/ivl/edif-s.conf
rm -f $(libdir)/ivl/edif.conf
-include $(patsubst %.o, dep/%.d, $O)

30
tgt-edif/configure.in Normal file
View File

@ -0,0 +1,30 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(edif.conf)
dnl Checks for programs.
AC_PROG_CC
AC_PROG_RANLIB
AC_PROG_INSTALL
AC_CHECK_PROGS(MAN,man,none)
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
AC_CANONICAL_HOST
# $host
# Combined check for Microsoft-related bogosities; sets WIN32 if found
AX_WIN32
AC_CHECK_HEADERS(malloc.h)
# may modify CPPFLAGS and CFLAGS
AX_CPP_PRECOMP
# Compiler option for position independent code, needed whan making shared objects.
AX_C_PICFLAG
# linker options when building a shared library
AX_LD_SHAREDLIB_OPTS
AX_CPP_IDENT
AC_OUTPUT(Makefile)

979
tgt-edif/d-lpm.c Normal file
View File

@ -0,0 +1,979 @@
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: d-lpm.c,v 1.1.2.2 2005/08/21 14:39:33 steve Exp $"
#endif
/*
* This is the driver for a purely generic LPM module writer. This
* uses LPM version 2 1 0 devices, without particularly considering
* the target technology.
*
* The LPM standard is EIA-IS/103-A October 1996
* The output is EDIF 2 0 0 format.
*/
# include "device.h"
# include "edif_priv.h"
# include "edif.h"
# include "generic.h"
# include <string.h>
# include <assert.h>
static edif_cell_t lpm_cell_buf(void)
{
static edif_cell_t tmp = 0;
if (tmp != 0)
return tmp;
tmp = edif_xcell_create(xlib, "BUF", 2);
edif_cell_portconfig(tmp, 0, "Result", IVL_SIP_OUTPUT);
edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT);
/* A buffer is an inverted inverter. */
edif_cell_port_pstring(tmp, 0, "LPM_Polarity", "INVERT");
edif_cell_pstring(tmp, "LPM_TYPE", "LPM_INV");
edif_cell_pinteger(tmp, "LPM_Width", 1);
edif_cell_pinteger(tmp, "LPM_Size", 1);
return tmp;
}
static edif_cell_t lpm_cell_inv(void)
{
static edif_cell_t tmp = 0;
if (tmp != 0)
return tmp;
tmp = edif_xcell_create(xlib, "INV", 2);
edif_cell_portconfig(tmp, 0, "Result", IVL_SIP_OUTPUT);
edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT);
edif_cell_pstring(tmp, "LPM_TYPE", "LPM_INV");
edif_cell_pinteger(tmp, "LPM_Width", 1);
edif_cell_pinteger(tmp, "LPM_Size", 1);
return tmp;
}
static edif_cell_t lpm_cell_bufif0(void)
{
static edif_cell_t tmp = 0;
if (tmp != 0)
return tmp;
tmp = edif_xcell_create(xlib, "BUFIF1", 3);
edif_cell_portconfig(tmp, 0, "TriData", IVL_SIP_OUTPUT);
edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT);
edif_cell_portconfig(tmp, 2, "EnableDT", IVL_SIP_INPUT);
edif_cell_port_pstring(tmp, 2, "LPM_Polarity", "INVERT");
edif_cell_pstring(tmp, "LPM_TYPE", "LPM_BUSTRI");
edif_cell_pinteger(tmp, "LPM_Width", 1);
return tmp;
}
static edif_cell_t lpm_cell_bufif1(void)
{
static edif_cell_t tmp = 0;
if (tmp != 0)
return tmp;
tmp = edif_xcell_create(xlib, "BUFIF1", 3);
edif_cell_portconfig(tmp, 0, "TriData", IVL_SIP_OUTPUT);
edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT);
edif_cell_portconfig(tmp, 2, "EnableDT", IVL_SIP_INPUT);
edif_cell_pstring(tmp, "LPM_TYPE", "LPM_BUSTRI");
edif_cell_pinteger(tmp, "LPM_Width", 1);
return tmp;
}
static edif_cell_t lpm_cell_or(unsigned siz)
{
unsigned idx;
edif_cell_t cell;
char name[32];
sprintf(name, "or%u", siz);
cell = edif_xlibrary_findcell(xlib, name);
if (cell != 0)
return cell;
cell = edif_xcell_create(xlib, strdup(name), siz+1);
edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT);
for (idx = 0 ; idx < siz ; idx += 1) {
sprintf(name, "Data%ux0", idx);
edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT);
}
edif_cell_pstring(cell, "LPM_TYPE", "LPM_OR");
edif_cell_pinteger(cell, "LPM_Width", 1);
edif_cell_pinteger(cell, "LPM_Size", siz);
return cell;
}
static edif_cell_t lpm_cell_and(unsigned siz)
{
unsigned idx;
edif_cell_t cell;
char name[32];
sprintf(name, "and%u", siz);
cell = edif_xlibrary_findcell(xlib, name);
if (cell != 0)
return cell;
cell = edif_xcell_create(xlib, strdup(name), siz+1);
edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT);
for (idx = 0 ; idx < siz ; idx += 1) {
sprintf(name, "Data%ux0", idx);
edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT);
}
edif_cell_pstring(cell, "LPM_TYPE", "LPM_AND");
edif_cell_pinteger(cell, "LPM_Width", 1);
edif_cell_pinteger(cell, "LPM_Size", siz);
return cell;
}
static edif_cell_t lpm_cell_xor(unsigned siz)
{
unsigned idx;
edif_cell_t cell;
char name[32];
sprintf(name, "xor%u", siz);
cell = edif_xlibrary_findcell(xlib, name);
if (cell != 0)
return cell;
cell = edif_xcell_create(xlib, strdup(name), siz+1);
edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT);
for (idx = 0 ; idx < siz ; idx += 1) {
sprintf(name, "Data%ux0", idx);
edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT);
}
edif_cell_pstring(cell, "LPM_TYPE", "LPM_XOR");
edif_cell_pinteger(cell, "LPM_Width", 1);
edif_cell_pinteger(cell, "LPM_Size", siz);
return cell;
}
static edif_cell_t lpm_cell_nor(unsigned siz)
{
unsigned idx;
edif_cell_t cell;
char name[32];
sprintf(name, "nor%u", siz);
cell = edif_xlibrary_findcell(xlib, name);
if (cell != 0)
return cell;
cell = edif_xcell_create(xlib, strdup(name), siz+1);
edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT);
edif_cell_port_pstring(cell, 0, "LPM_Polarity", "INVERT");
for (idx = 0 ; idx < siz ; idx += 1) {
sprintf(name, "Data%ux0", idx);
edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT);
}
edif_cell_pstring(cell, "LPM_TYPE", "LPM_OR");
edif_cell_pinteger(cell, "LPM_Width", 1);
edif_cell_pinteger(cell, "LPM_Size", siz);
return cell;
}
static void lpm_show_header(ivl_design_t des)
{
unsigned idx;
ivl_scope_t root = ivl_design_root(des);
unsigned sig_cnt = ivl_scope_sigs(root);
unsigned nports = 0, pidx;
/* Count the ports I'm going to use. */
for (idx = 0 ; idx < sig_cnt ; idx += 1) {
ivl_signal_t sig = ivl_scope_sig(root, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
if (ivl_signal_attr(sig, "PAD") != 0)
continue;
nports += ivl_signal_pins(sig);
}
/* Create the base edf object. */
edf = edif_create(ivl_scope_basename(root), nports);
pidx = 0;
for (idx = 0 ; idx < sig_cnt ; idx += 1) {
edif_joint_t jnt;
ivl_signal_t sig = ivl_scope_sig(root, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
if (ivl_signal_attr(sig, "PAD") != 0)
continue;
if (ivl_signal_pins(sig) == 1) {
edif_portconfig(edf, pidx, ivl_signal_basename(sig),
ivl_signal_port(sig));
assert(ivl_signal_pins(sig) == 1);
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0));
edif_port_to_joint(jnt, edf, pidx);
} else {
const char*name = ivl_signal_basename(sig);
ivl_signal_port_t dir = ivl_signal_port(sig);
char buf[128];
unsigned bit;
for (bit = 0 ; bit < ivl_signal_pins(sig) ; bit += 1) {
const char*tmp;
sprintf(buf, "%s[%u]", name, bit);
tmp = strdup(buf);
edif_portconfig(edf, pidx+bit, tmp, dir);
jnt = edif_joint_of_nexus(edf,ivl_signal_pin(sig,bit));
edif_port_to_joint(jnt, edf, pidx+bit);
}
}
pidx += ivl_signal_pins(sig);
}
assert(pidx == nports);
xlib = edif_xlibrary_create(edf, "LPM_LIBRARY");
}
static void lpm_show_footer(ivl_design_t des)
{
edif_print(xnf, edf);
}
static void hookup_logic_gate(ivl_net_logic_t net, edif_cell_t cell)
{
unsigned pin, idx;
edif_joint_t jnt;
edif_cellref_t ref = edif_cellref_create(edf, cell);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
pin = edif_cell_port_byname(cell, "Result0");
edif_add_to_joint(jnt, ref, pin);
for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) {
char name[32];
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx));
sprintf(name, "Data%ux0", idx-1);
pin = edif_cell_port_byname(cell, name);
edif_add_to_joint(jnt, ref, pin);
}
}
static void lpm_logic(ivl_net_logic_t net)
{
edif_cell_t cell;
edif_cellref_t ref;
edif_joint_t jnt;
switch (ivl_logic_type(net)) {
case IVL_LO_BUFZ:
case IVL_LO_BUF:
assert(ivl_logic_pins(net) == 2);
cell = lpm_cell_buf();
ref = edif_cellref_create(edf, cell);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, ref, 0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, ref, 1);
break;
case IVL_LO_BUFIF0:
assert(ivl_logic_pins(net) == 3);
cell = lpm_cell_bufif0();
ref = edif_cellref_create(edf, cell);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, ref, 0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, ref, 1);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
edif_add_to_joint(jnt, ref, 2);
break;
case IVL_LO_BUFIF1:
assert(ivl_logic_pins(net) == 3);
cell = lpm_cell_bufif1();
ref = edif_cellref_create(edf, cell);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, ref, 0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, ref, 1);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
edif_add_to_joint(jnt, ref, 2);
break;
case IVL_LO_NOT:
assert(ivl_logic_pins(net) == 2);
cell = lpm_cell_inv();
ref = edif_cellref_create(edf, cell);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, ref, 0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, ref, 1);
break;
case IVL_LO_OR:
cell = lpm_cell_or(ivl_logic_pins(net)-1);
hookup_logic_gate(net, cell);
break;
case IVL_LO_NOR:
cell = lpm_cell_nor(ivl_logic_pins(net)-1);
hookup_logic_gate(net, cell);
break;
case IVL_LO_AND:
cell = lpm_cell_and(ivl_logic_pins(net)-1);
hookup_logic_gate( net, cell);
break;
case IVL_LO_XOR:
cell = lpm_cell_xor(ivl_logic_pins(net)-1);
hookup_logic_gate( net, cell);
break;
default:
fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n",
ivl_logic_type(net));
break;
}
}
static void lpm_show_dff(ivl_lpm_t net)
{
char name[64];
edif_cell_t cell;
edif_cellref_t ref;
edif_joint_t jnt;
unsigned idx;
unsigned pin, wid = ivl_lpm_width(net);
sprintf(name, "fd%s%s%s%s%s%u",
ivl_lpm_enable(net)? "ce" : "",
ivl_lpm_async_clr(net)? "cl" : "",
ivl_lpm_sync_clr(net)? "sc" : "",
ivl_lpm_async_set(net)? "se" : "",
ivl_lpm_sync_set(net)? "ss" : "",
wid);
cell = edif_xlibrary_findcell(xlib, name);
if (cell == 0) {
unsigned nports = 2 * wid + 1;
pin = 0;
if (ivl_lpm_enable(net))
nports += 1;
if (ivl_lpm_async_clr(net))
nports += 1;
if (ivl_lpm_sync_clr(net))
nports += 1;
if (ivl_lpm_async_set(net))
nports += 1;
if (ivl_lpm_sync_set(net))
nports += 1;
cell = edif_xcell_create(xlib, strdup(name), nports);
edif_cell_pstring(cell, "LPM_Type", "LPM_FF");
edif_cell_pinteger(cell, "LPM_Width", wid);
for (idx = 0 ; idx < wid ; idx += 1) {
sprintf(name, "Q%u", idx);
edif_cell_portconfig(cell, idx*2+0, strdup(name),
IVL_SIP_OUTPUT);
sprintf(name, "Data%u", idx);
edif_cell_portconfig(cell, idx*2+1, strdup(name),
IVL_SIP_INPUT);
}
pin = wid*2;
if (ivl_lpm_enable(net)) {
edif_cell_portconfig(cell, pin, "Enable", IVL_SIP_INPUT);
pin += 1;
}
if (ivl_lpm_async_clr(net)) {
edif_cell_portconfig(cell, pin, "Aclr", IVL_SIP_INPUT);
pin += 1;
}
if (ivl_lpm_sync_clr(net)) {
edif_cell_portconfig(cell, pin, "Sclr", IVL_SIP_INPUT);
pin += 1;
}
if (ivl_lpm_async_set(net)) {
edif_cell_portconfig(cell, pin, "Aset", IVL_SIP_INPUT);
pin += 1;
}
if (ivl_lpm_sync_set(net)) {
edif_cell_portconfig(cell, pin, "Sset", IVL_SIP_INPUT);
pin += 1;
}
edif_cell_portconfig(cell, pin, "Clock", IVL_SIP_INPUT);
pin += 1;
assert(pin == nports);
}
ref = edif_cellref_create(edf, cell);
pin = edif_cell_port_byname(cell, "Clock");
jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net));
edif_add_to_joint(jnt, ref, pin);
if (ivl_lpm_enable(net)) {
pin = edif_cell_port_byname(cell, "Enable");
jnt = edif_joint_of_nexus(edf, ivl_lpm_enable(net));
edif_add_to_joint(jnt, ref, pin);
}
if (ivl_lpm_async_clr(net)) {
pin = edif_cell_port_byname(cell, "Aclr");
jnt = edif_joint_of_nexus(edf, ivl_lpm_async_clr(net));
edif_add_to_joint(jnt, ref, pin);
}
if (ivl_lpm_sync_clr(net)) {
pin = edif_cell_port_byname(cell, "Sclr");
jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_clr(net));
edif_add_to_joint(jnt, ref, pin);
}
if (ivl_lpm_async_set(net)) {
pin = edif_cell_port_byname(cell, "Aset");
jnt = edif_joint_of_nexus(edf, ivl_lpm_async_set(net));
edif_add_to_joint(jnt, ref, pin);
}
if (ivl_lpm_sync_set(net)) {
ivl_expr_t svalue = ivl_lpm_sset_value(net);
pin = edif_cell_port_byname(cell, "Sset");
jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_set(net));
edif_add_to_joint(jnt, ref, pin);
edif_cellref_pinteger(ref, "LPM_Svalue", ivl_expr_uvalue(svalue));
}
for (idx = 0 ; idx < wid ; idx += 1) {
sprintf(name, "Q%u", idx);
pin = edif_cell_port_byname(cell, name);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, ref, pin);
sprintf(name, "Data%u", idx);
pin = edif_cell_port_byname(cell, name);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, ref, pin);
}
}
static void lpm_show_cmp_eq(ivl_lpm_t net)
{
edif_cell_t cell;
edif_cellref_t ref;
edif_joint_t jnt;
unsigned idx;
char cellname[32];
unsigned width = ivl_lpm_width(net);
sprintf(cellname, "compare%u_eq", width);
cell = edif_xlibrary_findcell(xlib, cellname);
if (cell == 0) {
unsigned pins = 2*width + 1;
cell = edif_xcell_create(xlib, strdup(cellname), pins);
/* Make the output port. */
sprintf(cellname, "AEB");
edif_cell_portconfig(cell, 2*width, strdup(cellname),
IVL_SIP_OUTPUT);
for (idx = 0 ; idx < width ; idx += 1) {
sprintf(cellname, "DataA%u", idx);
edif_cell_portconfig(cell, idx+0, strdup(cellname),
IVL_SIP_INPUT);
}
for (idx = 0 ; idx < width ; idx += 1) {
sprintf(cellname, "DataB%u", idx);
edif_cell_portconfig(cell, idx+width, strdup(cellname),
IVL_SIP_INPUT);
}
edif_cell_pstring(cell, "LPM_Type", "LPM_COMPARE");
edif_cell_pinteger(cell, "LPM_Width", width);
}
ref = edif_cellref_create(edf, cell);
for (idx = 0 ; idx < width ; idx += 1) {
unsigned pin;
sprintf(cellname, "DataA%u", idx);
pin = edif_cell_port_byname(cell, cellname);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, ref, pin);
}
for (idx = 0 ; idx < width ; idx += 1) {
unsigned pin;
sprintf(cellname, "DataB%u", idx);
pin = edif_cell_port_byname(cell, cellname);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
edif_add_to_joint(jnt, ref, pin);
}
{
unsigned pin;
pin = edif_cell_port_byname(cell, "AEB");
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, ref, pin);
}
}
static void lpm_show_mux(ivl_lpm_t net)
{
edif_cell_t cell;
edif_cellref_t ref;
edif_joint_t jnt;
unsigned idx, rdx;
char cellname[32];
unsigned wid_r = ivl_lpm_width(net);
unsigned wid_s = ivl_lpm_selects(net);
unsigned wid_z = ivl_lpm_size(net);
sprintf(cellname, "mux%u_%u_%u", wid_r, wid_s, wid_z);
cell = edif_xlibrary_findcell(xlib, cellname);
if (cell == 0) {
unsigned pins = wid_r + wid_s + wid_r*wid_z;
cell = edif_xcell_create(xlib, strdup(cellname), pins);
/* Make the output ports. */
for (idx = 0 ; idx < wid_r ; idx += 1) {
sprintf(cellname, "Result%u", idx);
edif_cell_portconfig(cell, idx, strdup(cellname),
IVL_SIP_OUTPUT);
}
/* Make the select ports. */
for (idx = 0 ; idx < wid_s ; idx += 1) {
sprintf(cellname, "Sel%u", idx);
edif_cell_portconfig(cell, wid_r+idx, strdup(cellname),
IVL_SIP_INPUT);
}
for (idx = 0 ; idx < wid_z ; idx += 1) {
unsigned base = wid_r + wid_s + wid_r * idx;
unsigned rdx;
for (rdx = 0 ; rdx < wid_r ; rdx += 1) {
sprintf(cellname, "Data%ux%u", idx, rdx);
edif_cell_portconfig(cell, base+rdx, strdup(cellname),
IVL_SIP_INPUT);
}
}
edif_cell_pstring(cell, "LPM_Type", "LPM_MUX");
edif_cell_pinteger(cell, "LPM_Width", wid_r);
edif_cell_pinteger(cell, "LPM_WidthS", wid_s);
edif_cell_pinteger(cell, "LPM_Size", wid_z);
}
ref = edif_cellref_create(edf, cell);
/* Connect the pins of the instance to the nexa. Access the
cell pins by name. */
for (idx = 0 ; idx < wid_r ; idx += 1) {
unsigned pin;
sprintf(cellname, "Result%u", idx);
pin = edif_cell_port_byname(cell, cellname);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, ref, pin);
}
for (idx = 0 ; idx < wid_s ; idx += 1) {
unsigned pin;
sprintf(cellname, "Sel%u", idx);
pin = edif_cell_port_byname(cell, cellname);
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, idx));
edif_add_to_joint(jnt, ref, pin);
}
for (idx = 0 ; idx < wid_z ; idx += 1) {
for (rdx = 0 ; rdx < wid_r ; rdx += 1) {
unsigned pin;
sprintf(cellname, "Data%ux%u", idx, rdx);
pin = edif_cell_port_byname(cell, cellname);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, idx, rdx));
edif_add_to_joint(jnt, ref, pin);
}
}
}
static void lpm_show_add(ivl_lpm_t net)
{
unsigned idx;
unsigned cell_width;
char cellname[32];
edif_cell_t cell;
edif_cellref_t ref;
edif_joint_t jnt;
const char*type = "ADD";
if (ivl_lpm_type(net) == IVL_LPM_SUB)
type = "SUB";
/* Figure out the width of the cell. Normally, it is the LPM
width known by IVL. But if the top data input bits are
unconnected, then we really have a width one less, and we
can use the cout to fill out the output width. */
cell_width = ivl_lpm_width(net);
if ( (ivl_lpm_data(net,cell_width-1) == 0)
&& (ivl_lpm_datab(net,cell_width-1) == 0) )
cell_width -= 1;
/* Find the correct ADD/SUB device in the library, search by
name. If the device is not there, then create it and put it
in the library. */
sprintf(cellname, "%s%u", type, cell_width);
cell = edif_xlibrary_findcell(xlib, cellname);
if (cell == 0) {
unsigned pins = cell_width * 3 + 1;
cell = edif_xcell_create(xlib, strdup(cellname), pins);
for (idx = 0 ; idx < cell_width ; idx += 1) {
sprintf(cellname, "Result%u", idx);
edif_cell_portconfig(cell, idx*3+0, strdup(cellname),
IVL_SIP_OUTPUT);
sprintf(cellname, "DataA%u", idx);
edif_cell_portconfig(cell, idx*3+1, strdup(cellname),
IVL_SIP_INPUT);
sprintf(cellname, "DataB%u", idx);
edif_cell_portconfig(cell, idx*3+2, strdup(cellname),
IVL_SIP_INPUT);
}
edif_cell_portconfig(cell, pins-1, "Cout", IVL_SIP_OUTPUT);
edif_cell_pstring(cell, "LPM_Type", "LPM_ADD_SUB");
edif_cell_pstring(cell, "LPM_Direction", type);
edif_cell_pinteger(cell, "LPM_Width", ivl_lpm_width(net));
}
ref = edif_cellref_create(edf, cell);
/* Connect the pins of the instance to the nexa. Access the
cell pins by name. */
for (idx = 0 ; idx < cell_width ; idx += 1) {
unsigned pin;
sprintf(cellname, "Result%u", idx);
pin = edif_cell_port_byname(cell, cellname);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, ref, pin);
sprintf(cellname, "DataA%u", idx);
pin = edif_cell_port_byname(cell, cellname);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, ref, pin);
sprintf(cellname, "DataB%u", idx);
pin = edif_cell_port_byname(cell, cellname);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
edif_add_to_joint(jnt, ref, pin);
}
if (cell_width < ivl_lpm_width(net)) {
unsigned pin = edif_cell_port_byname(cell, "Cout");
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, cell_width));
edif_add_to_joint(jnt, ref, pin);
}
}
static void lpm_show_mult(ivl_lpm_t net)
{
char name[64];
unsigned idx;
edif_cell_t cell;
edif_cellref_t ref;
edif_joint_t jnt;
sprintf(name, "mult%u", ivl_lpm_width(net));
cell = edif_xlibrary_findcell(xlib, name);
if (cell == 0) {
cell = edif_xcell_create(xlib, strdup(name),
3 * ivl_lpm_width(net));
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
sprintf(name, "Result%u", idx);
edif_cell_portconfig(cell, idx*3+0,
strdup(name),
IVL_SIP_OUTPUT);
sprintf(name, "DataA%u", idx);
edif_cell_portconfig(cell, idx*3+1,
strdup(name),
IVL_SIP_INPUT);
sprintf(name, "DataB%u", idx);
edif_cell_portconfig(cell, idx*3+2,
strdup(name),
IVL_SIP_INPUT);
}
edif_cell_pstring(cell, "LPM_Type", "LPM_MULT");
edif_cell_pinteger(cell, "LPM_WidthP", ivl_lpm_width(net));
edif_cell_pinteger(cell, "LPM_WidthA", ivl_lpm_width(net));
edif_cell_pinteger(cell, "LPM_WidthB", ivl_lpm_width(net));
}
ref = edif_cellref_create(edf, cell);
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
unsigned pin;
ivl_nexus_t nex;
sprintf(name, "Result%u", idx);
pin = edif_cell_port_byname(cell, name);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, ref, pin);
if ( (nex = ivl_lpm_data(net, idx)) ) {
sprintf(name, "DataA%u", idx);
pin = edif_cell_port_byname(cell, name);
jnt = edif_joint_of_nexus(edf, nex);
edif_add_to_joint(jnt, ref, pin);
}
if ( (nex = ivl_lpm_datab(net, idx)) ) {
sprintf(name, "DataB%u", idx);
pin = edif_cell_port_byname(cell, name);
jnt = edif_joint_of_nexus(edf, nex);
edif_add_to_joint(jnt, ref, pin);
}
}
}
static void lpm_show_constant(ivl_net_const_t net)
{
/* We only need one instance each of constant 0 and 1 bits. If
we need either of them, then create an instance reference and
save that reference here so that later needs for 0 or 1 can
find that the reference already lives and can be added to the
joint. */
static edif_cellref_t cell0_ref = 0;
static edif_cellref_t cell1_ref = 0;
static edif_joint_t cell0_jnt = 0;
static edif_joint_t cell1_jnt = 0;
edif_cell_t cell0 = edif_xlibrary_findcell(xlib, "cell0");
edif_cell_t cell1 = edif_xlibrary_findcell(xlib, "cell1");
const char*bits;
unsigned idx;
if (cell0 == 0) {
cell0 = edif_xcell_create(xlib, "cell0", 1);
edif_cell_portconfig(cell0, 0, "Result0", IVL_SIP_OUTPUT);
edif_cell_pstring(cell0, "LPM_Type", "LPM_CONSTANT");
edif_cell_pinteger(cell0, "LPM_Width", 1);
edif_cell_pinteger(cell0, "LPM_CValue", 0);
}
if (cell1 == 0) {
cell1 = edif_xcell_create(xlib, "cell1", 1);
edif_cell_portconfig(cell1, 0, "Result0", IVL_SIP_OUTPUT);
edif_cell_pstring(cell1, "LPM_Type", "LPM_CONSTANT");
edif_cell_pinteger(cell1, "LPM_Width", 1);
edif_cell_pinteger(cell1, "LPM_CValue", 1);
}
bits = ivl_const_bits(net);
for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) {
if (bits[idx] == '1') {
if (cell1_ref == 0) {
cell1_ref = edif_cellref_create(edf, cell1);
cell1_jnt = edif_joint_create(edf);
edif_add_to_joint(cell1_jnt, cell1_ref, 0);
}
} else {
if (cell0_ref == 0) {
cell0_ref = edif_cellref_create(edf, cell0);
cell0_jnt = edif_joint_create(edf);
edif_add_to_joint(cell0_jnt, cell0_ref, 0);
}
}
}
for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) {
if (bits[idx] == '1')
edif_nexus_to_joint(edf, cell1_jnt, ivl_const_pin(net,idx));
else
edif_nexus_to_joint(edf, cell0_jnt, ivl_const_pin(net,idx));
}
}
const struct device_s d_lpm_edif = {
lpm_show_header,
lpm_show_footer,
0,
0, /* show_pad */
lpm_logic, /* show_logic */
lpm_show_dff, /* show_dff */
lpm_show_cmp_eq, /* show_cmp_eq */
0, /* show_cmp_ne */
0, /* show_cmp_ge */
0, /* show_cmp_gt */
lpm_show_mux, /* show_mux */
lpm_show_add, /* show_add */
lpm_show_add, /* show_sub */
0, /* show_shiftl */
0, /* show_shiftr */
lpm_show_mult, /* show_mult */
lpm_show_constant /* show_constant */
};
/*
* $Log: d-lpm.c,v $
* Revision 1.1.2.2 2005/08/21 14:39:33 steve
* Generate LPM for the CMP_EQ device.
*
* Revision 1.1.2.1 2005/08/17 01:17:28 steve
* Add the tgt-edif target.
*
*/

872
tgt-edif/d-virtex.c Normal file
View File

@ -0,0 +1,872 @@
/*
* Copyright (c) 2005 Stephen Williams (steve@icarus.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: d-virtex.c,v 1.1.2.1 2005/09/25 16:35:36 steve Exp $"
#endif
/*
* This is the driver for Xilinx Virtex style FPGA devices. The device
* table structure at the bottom of this file lists all the various
* functions that are used to generate code for virtex devices. In
* some cases this table uses entries that are common to all Xilinx
* devices, and in some cases Virtex specific entries are used. The
* Virtex specific functions are given here, the xilinx_* common
* functions are in the xilinx.{hc} source files.
*/
# include "device.h"
# include "edif.h"
# include "generic.h"
# include "xilinx.h"
# include <stdlib.h>
# include <string.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <assert.h>
/*
* This is a table of cell types that are accessible via the cellref
* attribute to a gate.
*/
const static struct edif_xlib_celltable virtex_celltable[] = {
{ "BUFG", xilinx_cell_bufg },
{ "MULT_AND", xilinx_cell_mult_and },
{ 0, 0}
};
/*
* The show_header function is called before any of the devices of the
* netlist are scanned.
*
* In this function, we look at the ports of the root module to decide
* if they are to be made into ports. Modules that have PAD attributes
* are *not* to be used as ports, they will be connected to special
* PAD devices instead.
*/
static void virtex_show_header(ivl_design_t des)
{
const char*part_str = 0;
xilinx_common_header(des);
xlib = edif_xlibrary_create(edf, "VIRTEX");
edif_xlibrary_set_celltable(xlib, virtex_celltable);
if ( (part_str = ivl_design_flag(des, "part")) && (part_str[0] != 0) ) {
edif_pstring(edf, "PART", part_str);
}
cell_0 = edif_xcell_create(xlib, "GND", 1);
edif_cell_portconfig(cell_0, 0, "GROUND", IVL_SIP_OUTPUT);
cell_1 = edif_xcell_create(xlib, "VCC", 1);
edif_cell_portconfig(cell_1, 0, "VCC", IVL_SIP_OUTPUT);
}
static void virtex_or_wide(ivl_net_logic_t net)
{
edif_cell_t cell_muxcy_l = xilinx_cell_muxcy_l(xlib);
edif_cell_t cell_muxcy = xilinx_cell_muxcy(xlib);
edif_cell_t cell_lut4 = xilinx_cell_lut4(xlib);
edif_cellref_t true_out, false_out;
edif_cellref_t lut, muxcy, muxcy_down=NULL;
edif_joint_t jnt;
unsigned idx, inputs, lut4_cnt;
if (ivl_logic_type(net) == IVL_LO_OR) {
true_out = edif_cellref_create(edf, cell_1);
false_out = edif_cellref_create(edf, cell_0);
} else {
true_out = edif_cellref_create(edf, cell_0);
false_out = edif_cellref_create(edf, cell_1);
}
inputs = ivl_logic_pins(net) - 1;
lut4_cnt = (inputs-1)/4;
for (idx = 0 ; idx < lut4_cnt ; idx += 1) {
muxcy = edif_cellref_create(edf, cell_muxcy_l);
lut = edif_cellref_create(edf, cell_lut4);
edif_cellref_pstring(lut, "INIT", "0001");
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, muxcy, MUXCY_S);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, true_out, 0);
edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+1));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+2));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+3));
edif_add_to_joint(jnt, lut, LUT_I3);
if (idx > 0) {
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, muxcy_down, MUXCY_O);
} else {
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, false_out, 0);
}
muxcy_down = muxcy;
}
muxcy = edif_cellref_create(edf, cell_muxcy);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, true_out, 0);
edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, muxcy_down, MUXCY_O);
switch (ivl_logic_pins(net) - 1 - lut4_cnt*4) {
case 1:
lut = edif_cellref_create(edf, xilinx_cell_inv(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0));
edif_add_to_joint(jnt, lut, BUF_I);
break;
case 2:
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
edif_cellref_pstring(lut, "INIT", "1");
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1));
edif_add_to_joint(jnt, lut, LUT_I1);
break;
case 3:
lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
edif_cellref_pstring(lut, "INIT", "01");
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+2));
edif_add_to_joint(jnt, lut, LUT_I2);
break;
case 4:
lut = edif_cellref_create(edf, cell_lut4);
edif_cellref_pstring(lut, "INIT", "0001");
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+2));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+3));
edif_add_to_joint(jnt, lut, LUT_I3);
break;
default:
assert(0);
}
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, muxcy, MUXCY_S);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, muxcy, MUXCY_O);
}
/*
* Pick off the cases where there is a Virtex specific implementation
* that is better then the generic Xilinx implementation. Route the
* remaining to the base xilinx_logic implementation.
*/
void virtex_logic(ivl_net_logic_t net)
{
/* Nothing I can do if the user expresses a specific
opinion. The cellref attribute forces me to let the base
xilinx_logic take care of it. */
if (ivl_logic_attr(net, "cellref")) {
xilinx_logic(net);
return;
}
switch (ivl_logic_type(net)) {
case IVL_LO_OR:
case IVL_LO_NOR:
if (ivl_logic_pins(net) <= 5) {
xilinx_logic(net);
} else {
virtex_or_wide(net);
}
break;
default:
xilinx_logic(net);
break;
}
}
void virtex_generic_dff(ivl_lpm_t net)
{
unsigned idx;
ivl_nexus_t aclr = ivl_lpm_async_clr(net);
ivl_nexus_t aset = ivl_lpm_async_set(net);
ivl_nexus_t sclr = ivl_lpm_sync_clr(net);
ivl_nexus_t sset = ivl_lpm_sync_set(net);
const char*abits = 0;
if (aset) {
ivl_expr_t avalue = ivl_lpm_aset_value(net);
assert(avalue);
abits = ivl_expr_bits(avalue);
assert(abits);
}
/* XXXX Can't handle both synchronous and asynchronous clear. */
assert( ! (aclr && sclr) );
/* XXXX Can't handle synchronous set at all. */
assert( ! sset );
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
edif_cellref_t obj;
ivl_nexus_t nex;
edif_joint_t jnt;
/* If there is a preset, then select an FDCPE instead of
an FDCE device. */
if (aset && (abits[idx] == '1')) {
obj = edif_cellref_create(edf, xilinx_cell_fdcpe(xlib));
} else if (aclr) {
obj = edif_cellref_create(edf, xilinx_cell_fdce(xlib));
} else if (sclr) {
obj = edif_cellref_create(edf, xilinx_cell_fdre(xlib));
} else {
obj = edif_cellref_create(edf, xilinx_cell_fdce(xlib));
}
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, obj, FDCE_Q);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, obj, FDCE_D);
jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net));
edif_add_to_joint(jnt, obj, FDCE_C);
if ( (nex = ivl_lpm_enable(net)) ) {
jnt = edif_joint_of_nexus(edf, nex);
edif_add_to_joint(jnt, obj, FDCE_CE);
}
if (aclr) {
jnt = edif_joint_of_nexus(edf, aclr);
edif_add_to_joint(jnt, obj, FDCE_CLR);
} else if (sclr) {
jnt = edif_joint_of_nexus(edf, sclr);
edif_add_to_joint(jnt, obj, FDCE_CLR);
}
if (aset) {
if (abits[idx] == '1') {
jnt = edif_joint_of_nexus(edf, aset);
edif_add_to_joint(jnt, obj, FDCE_PRE);
} else {
assert(aclr == 0);
jnt = edif_joint_of_nexus(edf, aset);
edif_add_to_joint(jnt, obj, FDCE_CLR);
}
}
}
}
/*
* This method handles both == and != operators, the identity
* comparison operators.
*
* If the identity compare is applied to small enough input vectors,
* it is shoved into a single LUT. Otherwise, it is strung out into a
* row of LUT devices chained together by carry muxes. The output of
* the comparison is the output of the last mux.
*
* When the compare is small, a LUT is generated with the appropriate
* truth table to cause an == or != result.
*
* When the compare is too wide for a single LUT, then it is made into
* a chain connected by a string of carry mux devices. Each LUT
* implements == for up to two pairs of bits, even if the final output
* is supposed to be !=. The LUT output is connected to an associated
* MUX select input. The CO output of each muxcy is passed up to the
* next higher order bits of the compare.
*
* For identity == compare, a != output from the LUT selects the DI
* input of the muxcy, generating a 0 output that is passed up. Since
* the next higher muxcy now gets a 0 input to both DI and CI, the
* output of the next higher muxcy is guaranteed to be 0, and so on to
* the final output of the carry chain. If the output from a LUT is ==,
* then the CI input of the muxcy is selected and the truth of this
* level depends on lower order bits. The least significant muxcy is
* connected to GND and VCC so that its CO follows the least
* significant LUT.
*
* Identity != is the same as == except that the output is
* inverted. To get that effect without putting an inverter on the
* output of the top muxcy pin CO (which would cost a LUT) the DI
* inputs are all connected to VCC instead of GND, and the CI of the
* least significant muxcy is connected to GND instead of VCC. The LUT
* expressions for the chained compare are configured for ==, with the
* changed CI/DI inputs performing the inversion.
*/
void virtex_eq(ivl_lpm_t net)
{
edif_cellref_t lut, mux, mux_prev;
edif_joint_t jnt, jnt_di;
unsigned idx;
/* True if I'm implementing CMP_EQ instead of CMP_NE */
int eq = 1;
assert(ivl_lpm_width(net) >= 1);
if (ivl_lpm_type(net) == IVL_LPM_CMP_NE)
eq = 0;
switch (ivl_lpm_width(net)) {
case 1:
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
edif_cellref_pstring(lut, "INIT", eq? "9" : "6");
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
return;
case 2:
lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
edif_cellref_pstring(lut, "INIT", eq? "9009" : "6FF6");
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1));
edif_add_to_joint(jnt, lut, LUT_I3);
return;
default:
{ edif_cellref_t di;
di = edif_cellref_create(edf, eq? cell_0 : cell_1);
jnt_di = edif_joint_create(edf);
edif_add_to_joint(jnt_di, di, 0);
}
mux_prev = 0;
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 2) {
int subwid = 2;
if ((idx + 1) == ivl_lpm_width(net))
subwid = 1;
mux = edif_cellref_create(edf, xilinx_cell_muxcy(xlib));
if (subwid == 2) {
lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
edif_cellref_pstring(lut, "INIT", "9009");
} else {
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
edif_cellref_pstring(lut, "INIT", "9");
}
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, mux, MUXCY_S);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
edif_add_to_joint(jnt, lut, LUT_I1);
if (subwid > 1) {
jnt = edif_joint_of_nexus(edf,
ivl_lpm_data(net, idx+1));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf,
ivl_lpm_datab(net, idx+1));
edif_add_to_joint(jnt, lut, LUT_I3);
}
edif_add_to_joint(jnt_di, mux, MUXCY_DI);
if (mux_prev) {
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, mux, MUXCY_CI);
edif_add_to_joint(jnt, mux_prev, MUXCY_O);
} else {
edif_cellref_t ci;
ci = edif_cellref_create(edf, eq? cell_1 : cell_0);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, ci, 0);
edif_add_to_joint(jnt, mux, MUXCY_CI);
}
mux_prev = mux;
}
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, mux_prev, MUXCY_O);
return;
}
}
/*
* Implement hardware for the device (A >= B). We use LUT devices if
* it can handle the slices, or carry chain logic if the slices must
* span LUT devices.
*/
void virtex_ge(ivl_lpm_t net)
{
edif_cellref_t muxcy_prev;
edif_cellref_t lut;
edif_joint_t jnt;
unsigned idx;
if (ivl_lpm_width(net) == 1) {
/* If the comparator is a single bit, then use a LUT2
with this truth table:
Q A B
--+----
1 | 0 0
0 | 0 1
1 | 1 0
1 | 1 1
Connect the A value to I1 and the B value to I0. */
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
edif_cellref_pstring(lut, "INIT", "D");
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I2);
return;
}
/* Handle the case where the device is two slices
wide. In this case, we can use a LUT4 to do all
the calculation. Use this truth table:
Q AA BB
--+------
1 | 00 00
0 | 00 01
0 | 00 10
0 | 00 11
1 | 01 00
1 | 01 01
0 | 01 10
0 | 01 11
1 | 10 00
1 | 10 01
1 | 10 10
0 | 10 11
1 | 11 xx
The I3-I0 inputs are A1 A0 B1 B0 in that order. */
assert(ivl_lpm_width(net) >= 2);
lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
edif_cellref_pstring(lut, "INIT", "F731");
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1));
edif_add_to_joint(jnt, lut, LUT_I3);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1));
edif_add_to_joint(jnt, lut, LUT_I1);
/* There are only two slices, so this is all we need. */
if (ivl_lpm_width(net) == 2) {
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
return;
}
/* The general case requires that we make the >= comparator
from slices. This is an iterative design. Each slice has
the truth table:
An Bn | A >= B
------+-------
0 0 | CI
0 1 | 0
1 0 | 1
1 1 | CI
The CI for each slice is the output of the compare of the
next less significant bits. We get this truth table by
connecting a LUT2 to the S input of a MUXCY. When the S
input is (1), it propagates its CI. This suggests that the
init value for the LUT be "9" (XNOR).
When the MUXCY S input is 0, it propagates a local
input. We connect to that input An, and we get the desired
and complete truth table for a slice.
This iterative definition needs to terminate at the least
significant bits. In fact, we have a non-iterative was to
deal with the two least significant slices. We take the
output of the LUT4 device for the least significant bits,
and use that to generate the initial CI for the chain. */
muxcy_prev = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib));
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, muxcy_prev, MUXCY_S);
{ edif_cellref_t p0 = edif_cellref_create(edf, cell_0);
edif_cellref_t p1 = edif_cellref_create(edf, cell_1);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, p0, 0);
edif_add_to_joint(jnt, muxcy_prev, MUXCY_DI);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, p1, 0);
edif_add_to_joint(jnt, muxcy_prev, MUXCY_CI);
}
for (idx = 2 ; idx < ivl_lpm_width(net) ; idx += 1) {
edif_cellref_t muxcy;
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
muxcy = edif_cellref_create(edf, xilinx_cell_muxcy(xlib));
edif_cellref_pstring(lut, "INIT", "9");
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, muxcy, MUXCY_S);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, muxcy_prev, MUXCY_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, lut, LUT_I0);
edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
edif_add_to_joint(jnt, lut, LUT_I1);
muxcy_prev = muxcy;
}
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, muxcy_prev, MUXCY_O);
}
/*
* A 4-input N-wide mux can be made on Virtex devices using MUXF5 and
* LUT devices. The MUXF5 selects a LUT device (and is connected to
* S[1]) and the LUT devices, connected to S[0], select the input.
*/
static void virtex_mux4(ivl_lpm_t net)
{
unsigned idx;
assert(ivl_lpm_selects(net) == 2);
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
edif_joint_t jnt;
edif_cellref_t lut01;
edif_cellref_t lut23;
edif_cellref_t muxf5;
lut01 = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
edif_cellref_pstring(lut01, "INIT", "CA");
lut23 = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
edif_cellref_pstring(lut23, "INIT", "CA");
muxf5 = edif_cellref_create(edf, xilinx_cell_muxf5(xlib));
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 0, idx));
edif_add_to_joint(jnt, lut01, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 1, idx));
edif_add_to_joint(jnt, lut01, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 2, idx));
edif_add_to_joint(jnt, lut23, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 3, idx));
edif_add_to_joint(jnt, lut23, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 0));
edif_add_to_joint(jnt, lut01, LUT_I2);
edif_add_to_joint(jnt, lut23, LUT_I2);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxf5, MUXF_I0);
edif_add_to_joint(jnt, lut01, LUT_O);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxf5, MUXF_I1);
edif_add_to_joint(jnt, lut23, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, muxf5, MUXF_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 1));
edif_add_to_joint(jnt, muxf5, MUXF_S);
}
}
void virtex_mux(ivl_lpm_t net)
{
switch (ivl_lpm_selects(net)) {
case 2:
virtex_mux4(net);
break;
default:
xilinx_mux(net);
break;
}
}
/*
* This function generates ADD/SUB devices for Virtex devices,
* based on the documented implementations of ADD8/ADD16, etc., from
* the Libraries Guide.
*
* Each slice of the ADD/SUB device is made from a LUT2 device, an
* XORCY device that mixes with the LUT2 to make a full adder, and a
* MUXCY_L to propagate the carry. The most significant slice does not
* have a carry to propagate, so has no MUXCY_L.
*
* If the device is a wide adder, then the LUT2 devices are configured
* to implement an XOR function and a zero is pumped into the least
* significant carry input.
*
* If the device is really an adder, then the input is turned into an
* XNOR, which takes a 1-s complement of the B input. Pump a 1 into
* the LSB carry input to finish converting the B input into the 2s
* complement.
*/
void virtex_add(ivl_lpm_t net)
{
const char*ha_init = 0;
edif_cellref_t lut, xorcy, muxcy, pad;
edif_joint_t jnt;
unsigned idx;
if (ivl_lpm_width(net) < 2) {
xilinx_add(net);
return;
}
switch (ivl_lpm_type(net)) {
case IVL_LPM_ADD:
ha_init = "6";
break;
case IVL_LPM_SUB:
ha_init = "9";
break;
default:
assert(0);
}
assert(ivl_lpm_width(net) > 1);
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib));
muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib));
edif_cellref_pstring(lut, "INIT", ha_init);
/* The bottom carry-in takes a constant that primes the add or
subtract. */
switch (ivl_lpm_type(net)) {
case IVL_LPM_ADD:
pad = edif_cellref_create(edf, cell_0);
break;
case IVL_LPM_SUB:
pad = edif_cellref_create(edf, cell_1);
break;
default:
assert(0);
}
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, pad, 0);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, xorcy, XORCY_CI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, xorcy, XORCY_O);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, xorcy, XORCY_LI);
edif_add_to_joint(jnt, muxcy, MUXCY_S);
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
for (idx = 1 ; idx < ivl_lpm_width(net) ; idx += 1) {
edif_cellref_t muxcy0 = muxcy;
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib));
edif_cellref_pstring(lut, "INIT", ha_init);
/* If this is the last bit, then there is no further
propagation in the carry chain, and I can skip the
carry mux MUXCY. */
if ((idx+1) < ivl_lpm_width(net))
muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib));
else
muxcy = 0;
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy0, MUXCY_O);
edif_add_to_joint(jnt, xorcy, XORCY_CI);
if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_CI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, xorcy, XORCY_O);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, xorcy, XORCY_LI);
if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_S);
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, lut, LUT_I0);
if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
edif_add_to_joint(jnt, lut, LUT_I1);
}
}
const struct device_s d_virtex_edif = {
virtex_show_header,
xilinx_show_footer,
xilinx_show_scope,
xilinx_pad,
virtex_logic,
virtex_generic_dff,
virtex_eq,
virtex_eq,
virtex_ge,
0, /* show_cmp_gt */
virtex_mux,
virtex_add,
virtex_add,
xilinx_shiftl,
0, /* show_shiftr */
0, /* show_mult */
0 /* show_constant */
};
/*
* $Log: d-virtex.c,v $
* Revision 1.1.2.1 2005/09/25 16:35:36 steve
* Add Xilinx virtex as a reference EDIF device.
*
*/

55
tgt-edif/device.c Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ident "$Id: device.c,v 1.1.2.1 2005/08/17 01:17:28 steve Exp $"
# include "device.h"
# include <string.h>
# include <assert.h>
device_t device_from_arch(const char*arch)
{
unsigned idx;
assert(arch);
for (idx = 0 ; edif_device_table[idx].name ; idx += 1) {
if (strcmp(arch, edif_device_table[idx].name) == 0)
return edif_device_table[idx].driver;
}
return 0;
}
/*
* $Log: device.c,v $
* Revision 1.1.2.1 2005/08/17 01:17:28 steve
* Add the tgt-edif target.
*
*/

101
tgt-edif/device.h Normal file
View File

@ -0,0 +1,101 @@
#ifndef __device_H
#define __device_H
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: device.h,v 1.1.2.1 2005/08/17 01:17:28 steve Exp $"
#endif
# include <ivl_target.h>
/*
* This code generator supports a variety of device types. It does
* this by keeping a device "driver" structure for each device
* type. The device structure contains pointers to functions that emit
* the proper XNF for a given type of device.
*
* If a device supports a method, the function pointer is filled in
* with a pointer to the proper function.
*
* If a device does not support the method, then the pointer is null.
*/
typedef const struct device_s* device_t;
struct device_s {
/* These methods draw leading and trailing format text. */
void (*show_header)(ivl_design_t des);
void (*show_footer)(ivl_design_t des);
/* Draw scopes marked by ivl_synthesis_cell */
void (*show_cell_scope)(ivl_scope_t net);
/* Draw pads connected to the specified signal. */
void (*show_pad)(ivl_signal_t sig, const char*str);
/* Draw basic logic devices. */
void (*show_logic)(ivl_net_logic_t net);
/* This method emits a D type Flip-Flop */
void (*show_dff)(ivl_lpm_t net);
/* These methods show various comparators */
void (*show_cmp_eq)(ivl_lpm_t net);
void (*show_cmp_ne)(ivl_lpm_t net);
void (*show_cmp_ge)(ivl_lpm_t net);
void (*show_cmp_gt)(ivl_lpm_t net);
/* This method draws MUX devices */
void (*show_mux)(ivl_lpm_t net);
/* This method draws ADD devices */
void (*show_add)(ivl_lpm_t net);
void (*show_sub)(ivl_lpm_t net);
/* These methods draw SHIFT devices */
void (*show_shiftl)(ivl_lpm_t net);
void (*show_shiftr)(ivl_lpm_t net);
/* Multipliers */
void (*show_mult)(ivl_lpm_t net);
/* Constants */
void (*show_constant)(ivl_net_const_t net);
};
/*
* Return the device_t cookie given the name of the architecture. If
* the device is not found, return 0.
*
* This function is used if the user specifies the archetecture
* explicitly, with the -parch=name flag.
*/
extern device_t device_from_arch(const char*arch);
/*
*/
extern const struct device_table_s {
const char*name;
device_t driver;
} edif_device_table[];
/*
* $Log: device.h,v $
* Revision 1.1.2.1 2005/08/17 01:17:28 steve
* Add the tgt-edif target.
*
*/
#endif

7
tgt-edif/edif-s.conf Normal file
View File

@ -0,0 +1,7 @@
functor:synth2
functor:synth
functor:syn-rules
#functor:cprop
functor:nodangle
-t:dll
flag:DLL=edif.tgt

681
tgt-edif/edif.c Normal file
View File

@ -0,0 +1,681 @@
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: edif.c,v 1.1.2.2 2005/08/21 22:25:51 steve Exp $"
#endif
# include "edif.h"
# include <stdlib.h>
# include <string.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <assert.h>
typedef enum property_e {
PRP_NONE = 0,
PRP_STRING,
PRP_INTEGER
} property_t;
struct cellref_property_ {
const char*name;
property_t ptype;
union {
const char*str;
long num;
} value_;
struct cellref_property_*next;
};
/*
* This is the root of an EDIF design. From here we can get at the
* root ports of the design (which are typically the pins of a chip or
* FPGA design) a list of external cell libraries, cells properties
* and nexa (joints).
*/
struct edif_s {
const char*name;
/* List the ports of the design. */
unsigned nports;
struct __cell_port*ports;
/* All the external libraries attached to me. */
edif_xlibrary_t xlibs;
/* list the cellref instances. */
edif_cellref_t celref;
/* The root instance has cellref properties as well. */
struct cellref_property_*property;
/* Keep a list of all the nexa */
struct edif_joint_s*nexa;
};
struct edif_xlibrary_s {
/* Name of this library. */
const char*name;
/* The cells that are contained in this library. */
struct edif_cell_s*cells;
/* point to the optional celltable. */
const struct edif_xlib_celltable*celltable;
/* used to list libraries in an edif_t. */
struct edif_xlibrary_s*next;
};
struct __cell_port {
const char*name;
const char*ename;
struct cellref_property_*property;
ivl_signal_port_t dir;
};
struct edif_cell_s {
const char*name;
edif_xlibrary_t xlib;
unsigned nports;
struct __cell_port*ports;
struct cellref_property_*property;
struct edif_cell_s*next;
};
struct edif_cellref_s {
struct edif_cell_s* cell;
unsigned u;
struct cellref_property_*property;
struct edif_cellref_s* next;
};
struct joint_cell_ {
struct edif_cellref_s*cell;
unsigned port;
struct joint_cell_*next;
};
/*
* Joints link cell ports together. The edif_t object contains a list
* of these joints, and each joint lists the ports that are connected
* together. The port is represented by a joint_cell_.
*
* The links list a singly linked list of joint_cell_ objects. To add
* a new link, simply push a new joint_cell_ into the links list. See
* the edif_add_to_joint and edif_port_to_joint functions.
*
* The joints themselves are kept in a singly linked list in the
* edif_t object. To create a new joint, simply push an initialized
* edif_joint_s onto the nexa member of the edif_t object. See the
* edif_joint_create function.
*/
struct edif_joint_s {
const char*name;
struct joint_cell_*links;
struct edif_joint_s*next;
};
static int is_edif_name(const char*text)
{
static const char*edif_name_chars = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
return (strspn(text, edif_name_chars) == strlen(text));
}
edif_t edif_create(const char*design_name, unsigned nports)
{
edif_t edf = malloc(sizeof(struct edif_s));
edf->name = design_name;
edf->nports= nports;
edf->ports = nports? calloc(nports, sizeof(struct __cell_port)) : 0;
edf->celref= 0;
edf->xlibs = 0;
edf->property = 0;
edf->nexa = 0;
return edf;
}
void edif_portconfig(edif_t edf, unsigned idx,
const char*name, ivl_signal_port_t dir)
{
assert(idx < edf->nports);
edf->ports[idx].name = name;
if (is_edif_name(name)) {
edf->ports[idx].ename = 0;
} else {
char buf[16];
sprintf(buf, "PORT%u", idx);
edf->ports[idx].ename = strdup(buf);
}
edf->ports[idx].dir = dir;
}
void edif_port_to_joint(edif_joint_t jnt, edif_t edf, unsigned port)
{
struct joint_cell_* jc = malloc(sizeof(struct joint_cell_));
jc->cell = 0;
jc->port = port;
jc->next = jnt->links;
jnt->links = jc;
}
void edif_pstring(edif_t edf, const char*name, const char*value)
{
struct cellref_property_*prp = malloc(sizeof(struct cellref_property_));
prp->name = name;
prp->ptype = PRP_STRING;
prp->value_.str = value;
prp->next = edf->property;
edf->property = prp;
}
edif_xlibrary_t edif_xlibrary_create(edif_t edf, const char*name)
{
edif_xlibrary_t xlib = malloc(sizeof(struct edif_xlibrary_s));
xlib->name = name;
xlib->cells = 0;
xlib->celltable = 0;
xlib->next = edf->xlibs;
edf->xlibs = xlib;
return xlib;
}
void edif_xlibrary_set_celltable(edif_xlibrary_t xlib,
const struct edif_xlib_celltable*tab)
{
assert(xlib->celltable == 0);
xlib->celltable = tab;
}
edif_cell_t edif_xlibrary_findcell(edif_xlibrary_t xlib,
const char*cell_name)
{
const struct edif_xlib_celltable*tcur;
edif_cell_t cur;
for (cur = xlib->cells ; cur ; cur = cur->next) {
if (strcmp(cell_name, cur->name) == 0)
return cur;
}
if (xlib->celltable == 0)
return 0;
for (tcur = xlib->celltable ; tcur->cell_name ; tcur += 1)
if (strcmp(cell_name, tcur->cell_name) == 0) {
return (tcur->cell_func)(xlib);
}
return 0;
}
edif_cell_t edif_xlibrary_scope_cell(edif_xlibrary_t xlib,
ivl_scope_t scope)
{
unsigned port_count, idx;
edif_cell_t cur;
/* Check to see if the cell is already somehow defined. */
cur = edif_xlibrary_findcell(xlib, ivl_scope_tname(scope));
if (cur) return cur;
/* Count the ports of the scope. */
port_count = 0;
for (idx = 0 ; idx < ivl_scope_sigs(scope) ; idx += 1) {
ivl_signal_t sig = ivl_scope_sig(scope, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
port_count += 1;
}
cur = edif_xcell_create(xlib, ivl_scope_tname(scope), port_count);
port_count = 0;
for (idx = 0 ; idx < ivl_scope_sigs(scope) ; idx += 1) {
ivl_signal_t sig = ivl_scope_sig(scope, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
edif_cell_portconfig(cur, port_count,
ivl_signal_basename(sig),
ivl_signal_port(sig));
port_count += 1;
}
return cur;
}
edif_cell_t edif_xcell_create(edif_xlibrary_t xlib, const char*name,
unsigned nports)
{
unsigned idx;
edif_cell_t cell = malloc(sizeof(struct edif_cell_s));
cell->name = name;
cell->xlib = xlib;
cell->nports = nports;
cell->ports = calloc(nports, sizeof(struct __cell_port));
cell->property = 0;
for (idx = 0 ; idx < nports ; idx += 1) {
cell->ports[idx].name = "?";
cell->ports[idx].dir = IVL_SIP_NONE;
cell->ports[idx].property = 0;
}
cell->next = xlib->cells;
xlib->cells = cell;
return cell;
}
void edif_cell_portconfig(edif_cell_t cell, unsigned idx,
const char*name, ivl_signal_port_t dir)
{
assert(idx < cell->nports);
cell->ports[idx].name = name;
cell->ports[idx].dir = dir;
}
void edif_cell_port_pstring(edif_cell_t cell, unsigned idx,
const char*name, const char*value)
{
struct cellref_property_*prp = malloc(sizeof(struct cellref_property_));
prp->name = name;
prp->ptype = PRP_STRING;
prp->value_.str = value;
prp->next = cell->ports[idx].property;
cell->ports[idx].property = prp;
}
unsigned edif_cell_port_byname(edif_cell_t cell, const char*name)
{
unsigned idx = 0;
for (idx = 0 ; idx < cell->nports ; idx += 1)
if (strcmp(name, cell->ports[idx].name) == 0)
break;
return idx;
}
void edif_cell_pstring(edif_cell_t cell, const char*name,
const char*value)
{
struct cellref_property_*prp = malloc(sizeof(struct cellref_property_));
prp->name = name;
prp->ptype = PRP_STRING;
prp->value_.str = value;
prp->next = cell->property;
cell->property = prp;
}
void edif_cell_pinteger(edif_cell_t cell, const char*name,
int value)
{
struct cellref_property_*prp = malloc(sizeof(struct cellref_property_));
prp->name = name;
prp->ptype = PRP_INTEGER;
prp->value_.num = value;
prp->next = cell->property;
cell->property = prp;
}
edif_cellref_t edif_cellref_create(edif_t edf, edif_cell_t cell)
{
static unsigned u_number = 0;
edif_cellref_t ref = malloc(sizeof(struct edif_cellref_s));
u_number += 1;
assert(cell);
assert(edf);
ref->u = u_number;
ref->cell = cell;
ref->property = 0;
ref->next = edf->celref;
edf->celref = ref;
return ref;
}
void edif_cellref_pstring(edif_cellref_t ref, const char*name,
const char*value)
{
struct cellref_property_*prp = malloc(sizeof(struct cellref_property_));
prp->name = name;
prp->ptype = PRP_STRING;
prp->value_.str = value;
prp->next = ref->property;
ref->property = prp;
}
void edif_cellref_pinteger(edif_cellref_t ref, const char*name, int value)
{
struct cellref_property_*prp = malloc(sizeof(struct cellref_property_));
prp->name = name;
prp->ptype = PRP_INTEGER;
prp->value_.num = value;
prp->next = ref->property;
ref->property = prp;
}
edif_joint_t edif_joint_create(edif_t edf)
{
edif_joint_t jnt = malloc(sizeof(struct edif_joint_s));
jnt->name = 0;
jnt->links = 0;
jnt->next = edf->nexa;
edf->nexa = jnt;
return jnt;
}
edif_joint_t edif_joint_of_nexus(edif_t edf, ivl_nexus_t nex)
{
void*tmp = ivl_nexus_get_private(nex);
edif_joint_t jnt;
if (tmp == 0) {
jnt = edif_joint_create(edf);
ivl_nexus_set_private(nex, jnt);
return jnt;
}
jnt = (edif_joint_t) tmp;
return jnt;
}
void edif_nexus_to_joint(edif_t edf, edif_joint_t jnt, ivl_nexus_t nex)
{
void*tmp = ivl_nexus_get_private(nex);
if (tmp != 0) {
/* There is a joint already on the nexus. Move all the
joint cells to the joint I'm joining to. */
edif_joint_t njnt = (edif_joint_t)tmp;
while (njnt->links) {
struct joint_cell_*cell = njnt->links;
njnt->links = cell->next;
cell->next = jnt->links;
jnt->links = cell;
}
/* Now njnt is dead, and should be removed from edif. */
/* Or we can ignore it as harmless. */
}
ivl_nexus_set_private(nex, jnt);
}
void edif_joint_rename(edif_joint_t jnt, const char*name)
{
assert(jnt->name == 0);
jnt->name = name;
}
void edif_add_to_joint(edif_joint_t jnt, edif_cellref_t cell, unsigned port)
{
struct joint_cell_* jc = malloc(sizeof(struct joint_cell_));
jc->cell = cell;
jc->port = port;
jc->next = jnt->links;
jnt->links = jc;
}
static void fprint_property(FILE*fd, const struct cellref_property_*prp)
{
fprintf(fd, "(property %s ", prp->name);
switch (prp->ptype) {
case PRP_NONE:
break;
case PRP_STRING:
fprintf(fd, "(string \"%s\")", prp->value_.str);
break;
case PRP_INTEGER:
fprintf(fd, "(integer %ld)", prp->value_.num);
break;
}
fprintf(fd, ")");
}
/*
* This function takes all the data structures that have been
* assembled by the code generator, and writes them into an EDIF
* formatted file.
*/
void edif_print(FILE*fd, edif_t edf)
{
edif_xlibrary_t xlib;
edif_cell_t cell;
edif_cellref_t ref;
edif_joint_t jnt;
struct cellref_property_*prp;
unsigned idx;
fprintf(fd, "(edif %s\n", edf->name);
fprintf(fd, " (edifVersion 2 0 0)\n");
fprintf(fd, " (edifLevel 0)\n");
fprintf(fd, " (keywordMap (keywordLevel 0))\n");
fprintf(fd, " (status\n");
fprintf(fd, " (written\n");
fprintf(fd, " (timeStamp 0 0 0 0 0 0)\n");
fprintf(fd, " (author \"unknown\")\n");
fprintf(fd, " (program \"Icarus Verilog/edif.tgt\")))\n");
fflush(fd);
for (xlib = edf->xlibs ; xlib ; xlib = xlib->next) {
fprintf(fd, " (external %s "
"(edifLevel 0) "
"(technology (numberDefinition))\n",
xlib->name);
for (cell = xlib->cells ; cell ; cell = cell->next) {
fprintf(fd, " (cell %s (cellType GENERIC)\n",
cell->name);
fprintf(fd, " (view net\n"
" (viewType NETLIST)\n"
" (interface");
for (idx = 0 ; idx < cell->nports ; idx += 1) {
struct __cell_port*pp = cell->ports + idx;
fprintf(fd, "\n (port %s", pp->name);
switch (pp->dir) {
case IVL_SIP_INPUT:
fprintf(fd, " (direction INPUT)");
break;
case IVL_SIP_OUTPUT:
fprintf(fd, " (direction OUTPUT)");
break;
case IVL_SIP_INOUT:
fprintf(fd, " (direction INOUT)");
break;
default:
break;
}
for (prp = pp->property ; prp ; prp=prp->next) {
fprintf(fd, " ");
fprint_property(fd, prp);
}
fprintf(fd, ")");
}
for (prp = cell->property ; prp ; prp = prp->next) {
fprintf(fd, "\n ");
fprint_property(fd, prp);
}
fprintf(fd, ")))\n");
}
fprintf(fd, " )\n"); /* terminate (external ...) sexp */
}
fflush(fd);
/* Write out the library header */
fprintf(fd, " (library DESIGN\n");
fprintf(fd, " (edifLevel 0)\n");
fprintf(fd, " (technology (numberDefinition))\n");
/* The root module is a cell in the library. */
fprintf(fd, " (cell %s\n", edf->name);
fprintf(fd, " (cellType GENERIC)\n");
fprintf(fd, " (view net\n");
fprintf(fd, " (viewType NETLIST)\n");
fprintf(fd, " (interface\n");
for (idx = 0 ; idx < edf->nports ; idx += 1) {
fprintf(fd, " (port ");
if (edf->ports[idx].ename == 0)
fprintf(fd, "%s ", edf->ports[idx].name);
else
fprintf(fd, "(rename %s \"%s\") ",
edf->ports[idx].ename,
edf->ports[idx].name);
switch (edf->ports[idx].dir) {
case IVL_SIP_INPUT:
fprintf(fd, "(direction INPUT)");
break;
case IVL_SIP_OUTPUT:
fprintf(fd, "(direction OUTPUT)");
break;
case IVL_SIP_INOUT:
fprintf(fd, "(direction INOUT)");
break;
default:
break;
}
fprintf(fd, ")\n");
}
fprintf(fd, " )\n"); /* end the (interface ) sexp */
fflush(fd);
fprintf(fd, " (contents\n");
/* Display all the instances. */
for (ref = edf->celref ; ref ; ref = ref->next) {
assert(ref->cell);
fprintf(fd, "(instance U%u (viewRef net "
"(cellRef %s (libraryRef %s)))",
ref->u, ref->cell->name, ref->cell->xlib->name);
for (prp = ref->property ; prp ; prp = prp->next) {
fprintf(fd, " ");
fprint_property(fd, prp);
}
fprintf(fd, ")\n");
}
fflush(fd);
/* Display all the joints. */
idx = 0;
for (jnt = edf->nexa ; jnt ; jnt = jnt->next, idx += 1) {
struct joint_cell_*jc;
/* Skip nil joints. */
if (jnt->links == 0)
continue;
fprintf(fd, "(net ");
if (jnt->name != 0)
fprintf(fd, "(rename N%u \"%s\")", idx, jnt->name);
else
fprintf(fd, "N%u", idx);
fprintf(fd, " (joined");
for (jc = jnt->links ; jc ; jc = jc->next) {
if (jc->cell) {
fprintf(fd, " (portRef %s (instanceRef U%u))",
jc->cell->cell->ports[jc->port].name,
jc->cell->u);
} else {
/* Reference to a port of the main cell. */
if (edf->ports[jc->port].ename)
fprintf(fd, " (portRef %s)",
edf->ports[jc->port].ename);
else
fprintf(fd, " (portRef %s)",
edf->ports[jc->port].name);
}
}
fprintf(fd, "))\n");
}
fprintf(fd, " )\n"); /* end the (contents...) sexp */
fprintf(fd, " )\n"); /* end the (view ) sexp */
fprintf(fd, " )\n"); /* end the (cell ) sexp */
fprintf(fd, " )\n"); /* end the (library DESIGN) sexp */
/* Make an instance of the defined object */
fprintf(fd, " (design %s\n", edf->name);
fprintf(fd, " (cellRef %s (libraryRef DESIGN))\n", edf->name);
for (prp = edf->property ; prp ; prp = prp->next) {
fprintf(fd, " ");
fprint_property(fd, prp);
fprintf(fd, "\n");
}
fprintf(fd, " )\n");
fprintf(fd, ")\n");
fflush(fd);
}
/*
* $Log: edif.c,v $
* Revision 1.1.2.2 2005/08/21 22:25:51 steve
* Fix the comment in the EDIT header.
*
* Revision 1.1.2.1 2005/08/17 01:17:28 steve
* Add the tgt-edif target.
*
*/

7
tgt-edif/edif.conf Normal file
View File

@ -0,0 +1,7 @@
functor:synth2
functor:synth
functor:syn-rules
functor:cprop
functor:nodangle
-t:dll
flag:DLL=edif.tgt

261
tgt-edif/edif.h Normal file
View File

@ -0,0 +1,261 @@
#ifndef __edif_H
#define __edif_H
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: edif.h,v 1.1.2.2 2005/09/25 16:35:36 steve Exp $"
#endif
# include <stdio.h>
# include <ivl_target.h>
/*
* These types and functions support the task of generating and
* writing out an EDIF 2 0 0 netlist. These functions work by
* supporting the creation of an in-core netlist of the design, then
* writing the netlist out all at once. The library manages cells with
* ports, but does not otherwise interpret cells. They have no
* contents.
*
* The general structure of netlist creation is as follows:
*
* Create a netlist with edif_create(<name>);
* This creates an edif object that represents the design. The
* design is given a name, and that name becomes the name of the
* single cell that this netlist handles.
*
* Add ports to the root with edif_portconfig
* The design may, if it is a macro to be included in a larger
* design, include ports. These are discovered by looking for port
* signals in the root module.
*
* Declare external libraries with edif_xlibrary_create
* Normally, this is the single technology library that contains
* the primitive cells that the code generator intendes to
* use. The library is given a name, such as VIRTEX or whatever
* the implementation tools expect. Cells are attached to the
* library later. An edif netlist may include multiple external
* references.
*
* Declare primitives with edif_xcell_create and edif_cell_portconfig.
* These functions create CELL TYPES that are attached to an
* external library. The libraries are created by
* edif_xlibrary_create.
*
* Cells can be created at any time before their first use. It
* therefore makes the most sense to not create the cell until it
* is certain that they are needed by the design.
*
* Create instances and join them up
* The edif_cellref_t objects represent instances of cells, and
* are the devices of the generated netlist. These cellrefs are
* connected together by the use of edif_joint_t joints. The
* joints can be created from ivl_nexus_t objects, or from their
* own ether. This instantiating of cells and joining them
* together that is the most fun. It is the technology specific
* stuff that the code generator does.
*
* Finally, print the result with edif_print(fd);
* This function writes the netlist in memory to an EDIF file on
* the stdio stream specified.
*
* This library is intended to be used once, to build up a netlist and
* print it. All the names that are taken as const char* should be
* somehow made permanent by the caller. Either they are constant
* strings, or they are strduped as necessary to make them
* permanent. The library will not duplicate them.
*/
/* TYPE DECLARATIONS */
/* This represents the entire EDIF design. You only need one of these
to hold everything. */
typedef struct edif_s* edif_t;
/* Each external library of the design gets one of these. */
typedef struct edif_xlibrary_s* edif_xlibrary_t;
/* This represents a type of cell. */
typedef struct edif_cell_s* edif_cell_t;
/* A cellref is an *instance* of a cell. */
typedef struct edif_cellref_s* edif_cellref_t;
/* This represents a generic joint. Cell ports are connected by being
associated with a joint. These can be bound to an ivl_nexus_t
object, of stand along. */
typedef struct edif_joint_s* edif_joint_t;
/* This structure defines a table that can be attached to an xlibrary
to incorporate black-box cells to the library. The cell_name is the
name that may be passed to the edif_xlibrary_findcell function, and
the function pointer points to a function that creates the cell and
defines ports for it. A real celltable is terminated by an entry
with a null pointer for the cell_name. */
struct edif_xlib_celltable {
const char*cell_name;
edif_cell_t (*cell_func)(edif_xlibrary_t xlib);
};
/* FUNCTIONS */
/* Start a new EDIF design. The design_name will be used as the name
of the top-mode module of the design. */
extern edif_t edif_create(const char*design_name, unsigned nports);
/* macro ports to the design are handled by this library similar to
cells. The user creates ports with this function. This function
configures the sole "port" of the cell with the name and dir passed
in. The direction, in this case, is the *interface* direction. */
extern void edif_portconfig(edif_t edf, unsigned idx,
const char*name, ivl_signal_port_t dir);
/* This is like edif_add_to_joint, but works with the edif port. */
extern void edif_port_to_joint(edif_joint_t jnt, edif_t edf, unsigned port);
/* The design may have properties attached to it. These properties
will be attached to the instance declared in the footer of the EDIF
file. */
extern void edif_pstring(edif_t edf, const char*name, const char*value);
/* Create an external library and attach it to the edif design. This
will lead to a (external ...) declaration of cells that can be used
by the design. */
extern edif_xlibrary_t edif_xlibrary_create(edif_t edf, const char*name);
extern void edif_xlibrary_set_celltable(edif_xlibrary_t lib,
const struct edif_xlib_celltable*table);
/* External libraries can be searched for existing cells, given a
string name. This function searches for the cell by name, and
returns it. */
extern edif_cell_t edif_xlibrary_findcell(edif_xlibrary_t lib,
const char*cell_name);
/* Similar to the above, but it gets the information it needs from the
ivl_scope_t object. */
extern edif_cell_t edif_xlibrary_scope_cell(edif_xlibrary_t xlib,
ivl_scope_t scope);
/* Create a new cell, attached to the external library. Specify the
number of ports that the cell has. The edif_cell_portconfig
function is then used to assign name and direction to each of the
ports.
The cell has a number of pins that are referenced by their number
from 0 to nports-1. You need to remember the pin numbers for the
named ports for use when joining that pin to an edif_joint_t.
Cellrefs get their port characteristics from the cell that they are
created from. So the pinouts of cellrefs match the pinout of the
associated cell. */
extern edif_cell_t edif_xcell_create(edif_xlibrary_t, const char*name,
unsigned nports);
extern void edif_cell_portconfig(edif_cell_t cell, unsigned idx,
const char*name, ivl_signal_port_t dir);
/* Attach a property to a cell port. */
extern void edif_cell_port_pstring(edif_cell_t cell, unsigned idx,
const char*name, const char*value);
/* Cells may have properties attached to them. These properties are
included in the library declaration for the cell, instead of the
cell instances. */
extern void edif_cell_pstring(edif_cell_t cell, const char*name,
const char*value);
extern void edif_cell_pinteger(edif_cell_t cell, const char*name,
int value);
/* Ports of cells are normally referenced by their port number. If you
forget what that number is, this function can look it up by name. */
extern unsigned edif_cell_port_byname(edif_cell_t cell, const char*name);
/* Create and instance from a cell. The instance refers to the cell,
which is a type, and contains pips for pins. */
extern edif_cellref_t edif_cellref_create(edif_t edf, edif_cell_t cell);
/* Instances can have properties attached to them. The name and value
given here are turned into a (property <name> (string "val"))
sexpression attached to the instance.
Examples of string properties commonly attached to cellref devices
include such things as the INIT=<value> to initialize LUT cells in
FPGA devices. */
extern void edif_cellref_pstring(edif_cellref_t ref, const char*name,
const char*value);
extern void edif_cellref_pinteger(edif_cellref_t ref, const char*name,
int value);
/* This function gets the joint associated with a nexus. This will
create a joint if necessary. */
extern edif_joint_t edif_joint_of_nexus(edif_t edf, ivl_nexus_t nex);
/* For linking cells outside the ivl netlist, this function creates an
anonymous joint. */
extern edif_joint_t edif_joint_create(edif_t edf);
/* Renaming a joint causes it to take on a name when external tools
view the EDIF file. */
extern void edif_joint_rename(edif_joint_t jnt, const char*name);
/* Given a joint, this function adds the cell reference. */
extern void edif_add_to_joint(edif_joint_t jnt,
edif_cellref_t cell,
unsigned port);
extern void edif_nexus_to_joint(edif_t edf, edif_joint_t jnt, ivl_nexus_t nex);
/*
* Print the entire design. This should only be done after the design
* is completely assembled.
*/
extern void edif_print(FILE*fd, edif_t design);
/*
* This is the fd that should be passed to the edif_print
* function. The name "xnf" is historical. This function is opened and
* closed automatically by the edif core (the target_design function)
* so generally there is no other use then the edif_print for this
* exposed fd.
*/
extern FILE*xnf;
/*
* $Log: edif.h,v $
* Revision 1.1.2.2 2005/09/25 16:35:36 steve
* Add Xilinx virtex as a reference EDIF device.
*
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*
*/
#endif

67
tgt-edif/edif_priv.h Normal file
View File

@ -0,0 +1,67 @@
#ifndef __fpga_priv_H
#define __fpga_priv_H
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: edif_priv.h,v 1.1.2.2 2005/09/25 16:35:36 steve Exp $"
#endif
# include <stdio.h>
# include "device.h"
extern int show_scope_gates(ivl_scope_t net, void*x);
extern device_t device;
extern const char*part;
extern const char*arch;
/*
* Attribute lookup, should this be provided in ivl_target.h?
*/
int scope_has_attribute(ivl_scope_t s, const char *name);
/*
* These are mangle functions.
*/
extern void xnf_mangle_logic_name(ivl_net_logic_t net, char*buf, size_t nbuf);
extern void xnf_mangle_lpm_name(ivl_lpm_t net, char*buf, size_t nbuf);
extern const char*xnf_mangle_nexus_name(ivl_nexus_t net);
/*
* $Log: edif_priv.h,v $
* Revision 1.1.2.2 2005/09/25 16:35:36 steve
* Add Xilinx virtex as a reference EDIF device.
*
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*
*/
#endif

192
tgt-edif/gates.c Normal file
View File

@ -0,0 +1,192 @@
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: gates.c,v 1.1.2.1 2005/08/17 01:17:29 steve Exp $"
#endif
# include <ivl_target.h>
# include "edif_priv.h"
# include <assert.h>
static void show_cell_scope(ivl_scope_t scope)
{
if (device->show_cell_scope == 0) {
fprintf(stderr, "fpga.tgt: ivl_synthesis_cell(scope)"
" not supported by this target.\n");
return;
}
device->show_cell_scope(scope);
}
static void show_gate_logic(ivl_net_logic_t net)
{
if (device->show_logic == 0) {
fprintf(stderr, "fpga.tgt: IVL LOGIC not supported"
" by this target.\n");
return;
}
assert(device->show_logic);
device->show_logic(net);
}
static void show_gate_lpm(ivl_lpm_t net)
{
switch (ivl_lpm_type(net)) {
case IVL_LPM_ADD:
if (device->show_add == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_ADD not supported"
" by this target.\n");
return;
}
device->show_add(net);
break;
case IVL_LPM_SUB:
if (device->show_sub == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_SUB not supported"
" by this target.\n");
return;
}
device->show_sub(net);
break;
case IVL_LPM_CMP_EQ:
if (device->show_cmp_eq == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_CMP_EQ not supported"
" by this target.\n");
return;
}
device->show_cmp_eq(net);
break;
case IVL_LPM_CMP_NE:
if (device->show_cmp_ne == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_CMP_NE not supported"
" by this target.\n");
return;
}
device->show_cmp_ne(net);
break;
case IVL_LPM_CMP_GE:
if (device->show_cmp_ge == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_CMP_GE not supported"
" by this target.\n");
return;
}
device->show_cmp_ge(net);
break;
case IVL_LPM_CMP_GT:
if (device->show_cmp_gt == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_CMP_GT not supported"
" by this target.\n");
return;
}
device->show_cmp_gt(net);
break;
case IVL_LPM_FF:
if (device->show_dff == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_FF not supported"
" by this target.\n");
return;
}
device->show_dff(net);
break;
case IVL_LPM_MUX:
if (device->show_mux == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_MUX not supported"
" by this target.\n");
return;
}
device->show_mux(net);
break;
case IVL_LPM_MULT:
if (device->show_mult == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_MULT not supported"
" by this target.\n");
return;
}
device->show_mult(net);
break;
case IVL_LPM_SHIFTL:
if (device->show_shiftl == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_SHIFTL not supported"
" by this target.\n");
return;
}
device->show_shiftl(net);
break;
case IVL_LPM_SHIFTR:
if (device->show_shiftr == 0) {
fprintf(stderr, "fpga.tgt: IVL_LPM_SHIFTR not supported"
" by this target.\n");
return;
}
device->show_shiftr(net);
break;
default:
fprintf(stderr, "fpga.tgt: unknown LPM type %u\n",
ivl_lpm_type(net));
break;
}
}
int show_scope_gates(ivl_scope_t net, void*x)
{
unsigned idx;
if (scope_has_attribute(net, "ivl_synthesis_cell")) {
show_cell_scope(net);
return 0;
}
for (idx = 0 ; idx < ivl_scope_logs(net) ; idx += 1)
show_gate_logic(ivl_scope_log(net, idx));
for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1)
show_gate_lpm(ivl_scope_lpm(net, idx));
return ivl_scope_children(net, show_scope_gates, 0);
}
/*
* $Log: gates.c,v $
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*
*/

51
tgt-edif/generic.c Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: generic.c,v 1.1.2.1 2005/08/17 01:17:29 steve Exp $"
#endif
# include "generic.h"
edif_t edf = 0;
edif_xlibrary_t xlib = 0;
edif_cell_t cell_0 = 0;
edif_cell_t cell_1 = 0;
edif_cell_t cell_ipad = 0;
edif_cell_t cell_opad = 0;
edif_cell_t cell_iopad = 0;
/*
* $Log: generic.c,v $
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*
*/

60
tgt-edif/generic.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef __generic_H
#define __generic_H
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: generic.h,v 1.1.2.1 2005/08/17 01:17:29 steve Exp $"
#endif
# include "edif.h"
extern edif_t edf;
extern edif_xlibrary_t xlib;
/*
* The cell_* variables below are the various kinds of devices that
* this family supports as primitives. If the cell type is used at
* least once, then the edif_cell_t is non-zero and will also be
* included in the library declaration. The constants underneath are
* pin assignments for the cell.
*/
extern edif_cell_t cell_0;
extern edif_cell_t cell_1;
extern edif_cell_t cell_ipad;
extern edif_cell_t cell_opad;
extern edif_cell_t cell_iopad;
/*
* $Log: generic.h,v $
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*
*/
#endif

59
tgt-edif/tables.c Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: tables.c,v 1.1.2.2 2005/09/25 16:35:37 steve Exp $"
#endif
# include "device.h"
# include <string.h>
# include <assert.h>
/*
* This is where you hook new device types into the module. Simply
* declare your struct device_s objects (as done with d_lpm_edif) and
* add an enty in to the edif_device_table so that the user may invoke
* it via the -parch=<foo> command line switch.
*/
extern const struct device_s d_lpm_edif;
extern const struct device_s d_virtex_edif;
const struct device_table_s edif_device_table[] = {
{ "lpm", &d_lpm_edif },
{ "virtex",&d_virtex_edif },
{ 0, 0 }
};
/*
* $Log: tables.c,v $
* Revision 1.1.2.2 2005/09/25 16:35:37 steve
* Add Xilinx virtex as a reference EDIF device.
*
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*
*/

238
tgt-edif/target.c Normal file
View File

@ -0,0 +1,238 @@
/*
* Copyright (c) 2005 Stephen Williams
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: target.c,v 1.1.2.1 2005/08/17 01:17:29 steve Exp $"
#endif
/*
* This is the EDIF target module.
*/
# include <ivl_target.h>
# include <string.h>
# include "edif_priv.h"
# include <assert.h>
/* This is the opened xnf file descriptor. It is the output that this
code generator writes to. */
FILE*xnf = 0;
const char*part = 0;
const char*arch = 0;
device_t device = 0;
int scope_has_attribute(ivl_scope_t s, const char *name)
{
int i;
const struct ivl_attribute_s *a;
for (i=0; i<ivl_scope_attr_cnt(s); i++) {
a = ivl_scope_attr_val(s, i);
if (strcmp(a->key,name) == 0)
return 1;
}
return 0;
}
static int show_process(ivl_process_t net, void*x)
{
ivl_scope_t scope = ivl_process_scope(net);
/* Ignore processes that are within scopes that are cells. The
cell_scope will generate a cell to represent the entire
scope. */
if (scope_has_attribute(scope, "ivl_synthesis_cell"))
return 0;
fprintf(stderr, "fpga target: unsynthesized behavioral code\n");
return 0;
}
static void show_pads(ivl_scope_t scope)
{
unsigned idx;
if (device->show_pad == 0)
return;
for (idx = 0 ; idx < ivl_scope_sigs(scope) ; idx += 1) {
ivl_signal_t sig = ivl_scope_sig(scope, idx);
const char*pad;
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
pad = ivl_signal_attr(sig, "PAD");
if (pad == 0)
continue;
assert(device->show_pad);
device->show_pad(sig, pad);
}
}
static void show_constants(ivl_design_t des)
{
unsigned idx;
if (device->show_constant == 0)
return;
for (idx = 0 ; idx < ivl_design_consts(des) ; idx += 1) {
ivl_net_const_t con = ivl_design_const(des, idx);
device->show_constant(con);
}
}
/*
* This is the main entry point that ivl uses to invoke me, the code
* generator.
*/
int target_design(ivl_design_t des)
{
ivl_scope_t root = ivl_design_root(des);
const char*path = ivl_design_flag(des, "-o");
xnf = fopen(path, "w");
if (xnf == 0) {
perror(path);
return -1;
}
part = ivl_design_flag(des, "part");
if (part && (part[0] == 0))
part = 0;
arch = ivl_design_flag(des, "arch");
if (arch && (arch[0] == 0))
arch = 0;
if (arch == 0)
arch = "lpm";
device = device_from_arch(arch);
if (device == 0) {
fprintf(stderr, "Unknown architecture arch=%s\n", arch);
return -1;
}
/* Call the device driver to generate the netlist header. */
device->show_header(des);
/* Catch any behavioral code that is left, and write warnings
that it is not supported. */
ivl_design_process(des, show_process, 0);
/* Get the pads from the design, and draw them to connect to
the associated signals. */
show_pads(root);
/* Scan the scopes, looking for gates to draw into the output
netlist. */
show_scope_gates(root, 0);
show_constants(des);
/* Call the device driver to close out the file. */
device->show_footer(des);
fclose(xnf);
xnf = 0;
return 0;
}
/*
* This function tests whether the nexus has a constant value. It
* returns true if the value is constant, or false if there are
* non-constant or conflicting drivers.
*/
int test_nexus_constant(ivl_nexus_t nex, char*val)
{
int count_drivers = 0;
unsigned idx;
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_net_const_t con;
unsigned pin;
const char*cbits;
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
/* If this nexus link is an input pin to the device (or
otherwise does not drive the nexus) then skip it. */
if (ivl_nexus_ptr_drive0(ptr) == IVL_DR_HiZ
&& ivl_nexus_ptr_drive1(ptr) == IVL_DR_HiZ)
continue;
count_drivers += 1;
/* If this driver is not a constant, then the test fails
certainly. */
con = ivl_nexus_ptr_con(ptr);
if (con == 0)
return 0;
/* Get the pin number within the constant where this
nexus is connected. */
pin = ivl_nexus_ptr_pin(ptr);
/* The pin for the constant that we located is
guaranteed to really point to the nexus that we are
working with. */
assert(ivl_const_pins(con) > pin);
assert(ivl_const_pin(con,pin) == nex);
/* Get the bit value from the constant. If there are
multiple constants driving this nexus (an unlikely
situation) then allow for them only if their value
matches. But the more common case is that this is the
only driver for the nexus. Save the constant value in
the *val result that we pass back to the user. */
cbits = ivl_const_bits(con);
if (count_drivers > 1) {
if (val[0] != cbits[pin])
return 0;
} else {
val[0] = cbits[pin];
}
}
/* If in the end there are no drivers at all for the nexus,
then assume the nexus has a constant HiZ value. */
if (count_drivers == 0)
*val = 'z';
/* Return TRUE */
return 1;
}
/*
* $Log: target.c,v $
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*
*/

980
tgt-edif/xilinx.c Normal file
View File

@ -0,0 +1,980 @@
/*
* Copyright (c) 2005 Stephen Williams (steve at icarus.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: xilinx.c,v 1.1.2.1 2005/09/25 16:35:37 steve Exp $"
#endif
/*
* This source file contains common functions used by Xilinx
* devices. The functions here do not support any specific Xilinx part
* fimily, but instead provide some core functions that are used by
* specific devices.
*
* For example, some xilinx_* functions are suitable for placing
* directly in a device_s table, but there is no "xilinx"
* device. These functions can be placed in the tables for devices
* that have no better way to handle the device_s function, or these
* functions can be called by device specific device_s functions that
* fall back on the generic handling in certain cases. For an example
* of both cases, see d-virtex.c.
*/
# include "edif.h"
# include "generic.h"
# include "xilinx.h"
# include <stdlib.h>
# include <string.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <assert.h>
edif_cell_t xilinx_cell_buf(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "BUF", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "BUFE", 3);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
edif_cell_portconfig(cell, BUF_T, "E", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "BUFG", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "BUFT", 3);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
edif_cell_portconfig(cell, BUF_T, "T", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "IBUF", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_inv(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "INV", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "MUXF5", 4);
edif_cell_portconfig(cell, MUXF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MUXF_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXF_I1, "I1", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXF_S, "S", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "MUXF6", 4);
edif_cell_portconfig(cell, MUXF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MUXF_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXF_I1, "I1", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXF_S, "S", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "OBUF", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "LUT2", 3);
edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "LUT3", 4);
edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I2, "I2", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "LUT4", 5);
edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I2, "I2", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I3, "I3", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "FDCE", 5);
edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CE, "CE", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CLR,"CLR", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "FDCPE", 6);
edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CE, "CE", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CLR,"CLR", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_PRE,"PRE", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "FDRE", 5);
edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CE, "CE", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CLR,"R", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "MULT_AND", 3);
edif_cell_portconfig(cell, MULT_AND_LO, "LO", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MULT_AND_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MULT_AND_I1, "I1", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "MUXCY", 4);
edif_cell_portconfig(cell, MUXCY_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MUXCY_DI, "DI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXCY_CI, "CI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXCY_S, "S", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "MUXCY_L", 4);
edif_cell_portconfig(cell, MUXCY_O, "LO", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MUXCY_DI, "DI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXCY_CI, "CI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXCY_S, "S", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "XORCY", 3);
edif_cell_portconfig(cell, XORCY_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, XORCY_CI, "CI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, XORCY_LI, "LI", IVL_SIP_INPUT);
return cell;
}
/*
* This function does a lot of the stuff common to the header
* functions of various Xilinx familes. This includes creating the edf
* object that holds the netlist.
*/
void xilinx_common_header(ivl_design_t des)
{
unsigned idx;
ivl_scope_t root = ivl_design_root(des);
unsigned sig_cnt = ivl_scope_sigs(root);
unsigned nports = 0, pidx;
/* Count the ports I'm going to use. */
for (idx = 0 ; idx < sig_cnt ; idx += 1) {
ivl_signal_t sig = ivl_scope_sig(root, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
if (ivl_signal_attr(sig, "PAD") != 0)
continue;
nports += ivl_signal_pins(sig);
}
edf = edif_create(ivl_scope_basename(root), nports);
pidx = 0;
for (idx = 0 ; idx < sig_cnt ; idx += 1) {
edif_joint_t jnt;
ivl_signal_t sig = ivl_scope_sig(root, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
if (ivl_signal_attr(sig, "PAD") != 0)
continue;
if (ivl_signal_pins(sig) == 1) {
edif_portconfig(edf, pidx, ivl_signal_basename(sig),
ivl_signal_port(sig));
assert(ivl_signal_pins(sig) == 1);
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0));
edif_port_to_joint(jnt, edf, pidx);
} else {
const char*name = ivl_signal_basename(sig);
ivl_signal_port_t dir = ivl_signal_port(sig);
char buf[128];
unsigned bit;
for (bit = 0 ; bit < ivl_signal_pins(sig) ; bit += 1) {
const char*tmp;
sprintf(buf, "%s[%u]", name, bit);
tmp = strdup(buf);
edif_portconfig(edf, pidx+bit, tmp, dir);
jnt = edif_joint_of_nexus(edf,ivl_signal_pin(sig,bit));
edif_port_to_joint(jnt, edf, pidx+bit);
}
}
pidx += ivl_signal_pins(sig);
}
assert(pidx == nports);
}
void xilinx_show_footer(ivl_design_t des)
{
unsigned idx;
for (idx = 0 ; idx < ivl_design_consts(des) ; idx += 1) {
unsigned pin;
ivl_net_const_t net = ivl_design_const(des, idx);
const char*val = ivl_const_bits(net);
for (pin = 0 ; pin < ivl_const_pins(net) ; pin += 1) {
edif_joint_t jnt;
edif_cellref_t pad;
jnt = edif_joint_of_nexus(edf, ivl_const_pin(net, pin));
switch (val[pin]) {
case '0':
pad = edif_cellref_create(edf, cell_0);
break;
case '1':
pad = edif_cellref_create(edf, cell_1);
break;
default:
assert(0);
break;
}
edif_add_to_joint(jnt, pad, 0);
}
}
edif_print(xnf, edf);
}
/*
* Make (or retrieve) a cell in the external library that reflects the
* scope with its ports.
*/
void xilinx_show_scope(ivl_scope_t scope)
{
edif_cell_t cell;
edif_cellref_t ref;
unsigned port, idx;
cell = edif_xlibrary_scope_cell(xlib, scope);
ref = edif_cellref_create(edf, cell);
for (idx = 0 ; idx < ivl_scope_sigs(scope) ; idx += 1) {
edif_joint_t jnt;
ivl_signal_t sig = ivl_scope_sig(scope, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
port = edif_cell_port_byname(cell, ivl_signal_basename(sig));
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0));
edif_add_to_joint(jnt, ref, port);
}
}
void xilinx_pad(ivl_signal_t sig, const char*str)
{
unsigned idx;
char**pins;
if (cell_ipad == 0) {
cell_ipad = edif_xcell_create(xlib, "IPAD", 1);
edif_cell_portconfig(cell_ipad, 0, "IPAD", IVL_SIP_OUTPUT);
}
if (cell_opad == 0) {
cell_opad = edif_xcell_create(xlib, "OPAD", 1);
edif_cell_portconfig(cell_opad, 0, "OPAD", IVL_SIP_INPUT);
}
if (cell_iopad == 0) {
cell_iopad = edif_xcell_create(xlib, "IOPAD", 1);
edif_cell_portconfig(cell_iopad, 0, "IOPAD", IVL_SIP_INOUT);
}
/* Collect an array of pin assignments from the attribute
string passed in as str. The format is a comma separated
list of location names. */
pins = calloc(ivl_signal_pins(sig), sizeof(char*));
for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) {
const char*tmp = strchr(str, ',');
if (tmp == 0) tmp = str+strlen(str);
pins[idx] = malloc(tmp-str+1);
strncpy(pins[idx], str, tmp-str);
pins[idx][tmp-str] = 0;
if (*tmp != 0)
tmp += 1;
str = tmp;
}
/* Now go through the pins of the signal, creating pads and
bufs and joining them to the signal nexus. */
for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) {
edif_joint_t jnt;
edif_cellref_t pad, buf;
const char*name_str = ivl_signal_basename(sig);
if (ivl_signal_pins(sig) > 1) {
char name_buf[128];
sprintf(name_buf, "%s[%u]", name_str, idx);
name_str = strdup(name_buf);
}
switch (ivl_signal_port(sig)) {
case IVL_SIP_INPUT:
pad = edif_cellref_create(edf, cell_ipad);
buf = edif_cellref_create(edf, xilinx_cell_ibuf(xlib));
jnt = edif_joint_create(edf);
edif_joint_rename(jnt, name_str);
edif_add_to_joint(jnt, pad, 0);
edif_add_to_joint(jnt, buf, BUF_I);
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx));
edif_add_to_joint(jnt, buf, BUF_O);
break;
case IVL_SIP_OUTPUT:
pad = edif_cellref_create(edf, cell_opad);
buf = edif_cellref_create(edf, xilinx_cell_obuf(xlib));
jnt = edif_joint_create(edf);
edif_joint_rename(jnt, name_str);
edif_add_to_joint(jnt, pad, 0);
edif_add_to_joint(jnt, buf, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx));
edif_add_to_joint(jnt, buf, BUF_I);
break;
case IVL_SIP_INOUT:
pad = edif_cellref_create(edf, cell_iopad);
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx));
edif_add_to_joint(jnt, pad, 0);
break;
default:
assert(0);
}
if (pins[idx])
edif_cellref_pstring(pad, "LOC", pins[idx]);
}
/* Don't free the allocated pad name strings. The
edif_cellref_pstring function attached the string to the
LOC attribute, so the reference is permanent. */
free(pins);
}
/*
* This function handles the case where the user specifies the cell to
* use by attribute.
*/
static void edif_cellref_logic(ivl_net_logic_t net, const char*def)
{
char*str = strdup(def);
char*pins;
edif_cell_t cell;
edif_cellref_t ref;
edif_joint_t jnt;
unsigned idx, port;
pins = strchr(str, ':');
assert(pins);
*pins++ = 0;
/* Locate the cell in the library, lookup by name. */
cell = edif_xlibrary_findcell(xlib, str);
assert(cell);
ref = edif_cellref_create(edf, cell);
for (idx = 0 ; idx < ivl_logic_pins(net) ; idx += 1) {
char*tmp;
assert(pins);
tmp = strchr(pins,',');
if (tmp != 0)
*tmp++ = 0;
else
tmp = 0;
port = edif_cell_port_byname(cell, pins);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx));
edif_add_to_joint(jnt, ref, port);
pins = tmp;
}
free(str);
}
static void lut_logic(ivl_net_logic_t net, const char*init3,
const char*init4, const char*init5)
{
edif_cellref_t lut = NULL; /* initialization shuts up gcc -Wall */
edif_joint_t jnt;
const char* init = NULL; /* ditto */
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
switch (ivl_logic_pins(net)) {
case 3:
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
init = init3;
break;
case 4:
lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
init = init4;
break;
case 5:
lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
init = init5;
break;
}
edif_cellref_pstring(lut, "INIT", init);
switch (ivl_logic_pins(net)) {
case 5:
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 4));
edif_add_to_joint(jnt, lut, LUT_I3);
case 4:
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 3));
edif_add_to_joint(jnt, lut, LUT_I2);
case 3:
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
edif_add_to_joint(jnt, lut, LUT_I1);
}
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
}
void xilinx_logic(ivl_net_logic_t net)
{
edif_cellref_t obj;
edif_joint_t jnt;
{ const char*cellref_attribute = ivl_logic_attr(net, "cellref");
if (cellref_attribute != 0) {
edif_cellref_logic(net, cellref_attribute);
return;
}
}
switch (ivl_logic_type(net)) {
case IVL_LO_BUF:
case IVL_LO_BUFZ:
assert(ivl_logic_pins(net) == 2);
obj = edif_cellref_create(edf, xilinx_cell_buf(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, obj, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, obj, BUF_I);
break;
case IVL_LO_BUFIF0:
/* The Xilinx BUFT devices is a BUF that adds a T
input. The output is tri-stated if the T input is
1. In other words, it acts just like bufif0. */
assert(ivl_logic_pins(net) == 3);
obj = edif_cellref_create(edf, xilinx_cell_buft(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, obj, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, obj, BUF_I);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
edif_add_to_joint(jnt, obj, BUF_T);
break;
case IVL_LO_BUFIF1:
/* The Xilinx BUFE devices is a BUF that adds an enable
input. The output is tri-stated if the E input is 0.
In other words, it acts just like bufif1. */
assert(ivl_logic_pins(net) == 3);
obj = edif_cellref_create(edf, xilinx_cell_bufe(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, obj, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, obj, BUF_I);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
edif_add_to_joint(jnt, obj, BUF_T);
break;
case IVL_LO_NOT:
assert(ivl_logic_pins(net) == 2);
obj = edif_cellref_create(edf, xilinx_cell_inv(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, obj, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, obj, BUF_I);
break;
case IVL_LO_AND:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "8", "80", "8000");
break;
case IVL_LO_NOR:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "1", "01", "0001");
break;
case IVL_LO_OR:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "E", "FE", "FFFE");
break;
case IVL_LO_XNOR:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "9", "69", "9669");
break;
case IVL_LO_XOR:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "6", "96", "6996");
break;
default:
fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n",
ivl_logic_type(net));
break;
}
}
/*
* A fully generic Xilinx MUX is implemented entirely from LUT
* devices.
*/
void xilinx_mux(ivl_lpm_t net)
{
unsigned idx;
edif_cellref_t lut;
edif_joint_t jnt;
assert(ivl_lpm_selects(net) == 1);
/* A/B Mux devices are made from LUT3 devices. I0 is connected
to A, I1 to B, and I2 to the Select input. Create as many
as are needed to implement the requested width.
S B A | Q
------+--
0 0 0 | 0
0 0 1 | 1
0 1 0 | 0
0 1 1 | 1
1 0 0 | 0
1 0 1 | 0
1 1 0 | 1
1 1 1 | 1
INIT = "CA" */
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 0, idx));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 1, idx));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 0));
edif_add_to_joint(jnt, lut, LUT_I2);
edif_cellref_pstring(lut, "INIT", "CA");
}
}
/*
* Any Xilinx device works with this adder.
* Generic Xilinx add only works for single bit slices.
*/
void xilinx_add(ivl_lpm_t net)
{
const char*ha_init = 0;
edif_cellref_t lut;
edif_joint_t jnt;
switch (ivl_lpm_type(net)) {
case IVL_LPM_ADD:
ha_init = "6";
break;
case IVL_LPM_SUB:
ha_init = "9";
break;
default:
assert(0);
}
/* If this is a single bit wide, then generate only a
half-adder. Normally this is an XOR, but if this is a SUB
then it is an XNOR. */
if (ivl_lpm_width(net) == 1) {
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
edif_cellref_pstring(lut, "INIT", ha_init);
return;
}
assert(0);
}
/*
* The left shift is implemented as a matrix of MUX2_1 devices. The
* matrix has as many rows as the device width, and a column for each
* select.
*/
void xilinx_shiftl(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
unsigned nsel = 0, swid = 0;
unsigned sdx, qdx;
edif_cellref_t* cells;
edif_cellref_t**table;
edif_cellref_t pad0_cell;
edif_joint_t pad0;
/* First, find out how many select inputs we really need. We
can only use the selects that are enough to shift out the
entire width of the device. The excess can be used as an
enable for the last column. When disabled, the last column
emits zeros. */
while (nsel < ivl_lpm_selects(net)) {
nsel += 1;
swid = 1 << nsel;
if (swid >= width)
break;
}
assert(nsel > 0);
/* Allocate a matrix of edif_cellref_t variables. A devices
will be addressed by the expression table[sdx][qdx];
This should make the algorighm code easier to read. */
cells = calloc(nsel * width, sizeof(edif_cellref_t));
table = calloc(nsel, sizeof(edif_cellref_t*));
for (sdx = 0 ; sdx < nsel ; sdx += 1)
table[sdx] = cells + sdx*width;
/* Make a 0 valued pad bit. I wlil use this for all the shifin
values that are beyond the input. */
pad0_cell = edif_cellref_create(edf, cell_0);
pad0 = edif_joint_create(edf);
edif_add_to_joint(pad0, pad0_cell, 0);
/* The LUT matrix is <nsel> columns of <width> devices, with
the last column a LUT4 devices. The extra input of the
LUT4s in the last column are used as an enable to collect
all the excess select inputs. */
/* Allocate the LUT devices of the matrix, and connect the
select inputs to I2 of all the devices of the column. */
for (sdx = 0 ; sdx < nsel ; sdx += 1) {
const char*init_string = 0;
ivl_nexus_t nex = ivl_lpm_select(net,sdx);
edif_joint_t sdx_jnt = edif_joint_of_nexus(edf, nex);
edif_cell_t lut;
if (((sdx+1) == nsel) && (nsel < ivl_lpm_selects(net))) {
lut = xilinx_cell_lut4(xlib);
init_string = "00CA";
} else {
lut = xilinx_cell_lut3(xlib);
init_string = "CA";
}
for (qdx = 0 ; qdx < width ; qdx += 1) {
table[sdx][qdx] = edif_cellref_create(edf, lut);
edif_add_to_joint(sdx_jnt, table[sdx][qdx], LUT_I2);
edif_cellref_pstring(table[sdx][qdx], "INIT", init_string);
}
}
/* Connect the inputs of the SHIFTL device to the column 0 LUT
inputs. The slice on the low end shifts in a 0 for a select
input. */
for (qdx = 0 ; qdx < width ; qdx += 1) {
ivl_nexus_t nex0, nex1;
edif_joint_t jnt0;
edif_joint_t jnt1;
nex0 = ivl_lpm_data(net,qdx);
jnt0 = edif_joint_of_nexus(edf, nex0);
if (qdx > 0) {
nex1 = ivl_lpm_data(net,qdx-1);
jnt1 = edif_joint_of_nexus(edf, nex1);
} else {
jnt1 = pad0;
}
edif_add_to_joint(jnt0, table[0][qdx], LUT_I0);
edif_add_to_joint(jnt1, table[0][qdx], LUT_I1);
}
/* Make the inner connections between LUT devices. Each column
connects to the previous column, shifted by the power of
the column value. If the shifted input falls off the end,
then pad with zero. */
for (sdx = 1 ; sdx < nsel ; sdx += 1) {
for (qdx = 0 ; qdx < width ; qdx += 1) {
unsigned shift = 1 << sdx;
edif_joint_t jnt0 = edif_joint_create(edf);
edif_joint_t jnt1 = (qdx >= shift)
? edif_joint_create(edf)
: pad0;
edif_add_to_joint(jnt0, table[sdx][qdx], LUT_I0);
edif_add_to_joint(jnt1, table[sdx][qdx], LUT_I1);
edif_add_to_joint(jnt0, table[sdx-1][qdx], LUT_O);
if (qdx >= shift)
edif_add_to_joint(jnt1, table[sdx-1][qdx-shift], LUT_O);
}
}
/* Connect the output of the last column to the output of the
SHIFTL device. */
for (qdx = 0 ; qdx < width ; qdx += 1) {
ivl_nexus_t nex = ivl_lpm_q(net,qdx);
edif_joint_t jnt = edif_joint_of_nexus(edf, nex);
edif_add_to_joint(jnt, table[nsel-1][qdx], LUT_O);
}
/* Connect the excess select inputs to the enable inputs of
the LUT4 devices in the last column. */
if (nsel < ivl_lpm_selects(net)) {
edif_joint_t jnt;
/* XXXX Only support 1 excess bit for now. */
assert((nsel + 1) == ivl_lpm_selects(net));
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net,nsel));
for (qdx = 0 ; qdx < width ; qdx += 1)
edif_add_to_joint(jnt, table[nsel-1][qdx], LUT_I3);
}
free(cells);
free(table);
}
/*
* $Log: xilinx.c,v $
* Revision 1.1.2.1 2005/09/25 16:35:37 steve
* Add Xilinx virtex as a reference EDIF device.
*
*/

149
tgt-edif/xilinx.h Normal file
View File

@ -0,0 +1,149 @@
#ifndef __xilinx_H
#define __xilinx_H
/*
* Copyright (c) 2005 Stephen Williams (steve at icarus.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: xilinx.h,v 1.1.2.1 2005/09/25 16:35:37 steve Exp $"
#endif
/*
* This header file includes XILINX library support functions. They
* manage the creation and reference of cells from the library. Use
* the xililx_cell_* functions to get an edif_cell_t from the
* library. The function will create the cell in the library if
* needed, or will return the existing cell if it was already called.
*
* Note that these functions are *not* part of the baseline EDIF. They
* are intended to be Xilinx specific and sometimes do things that
* would be flat-out wrong for non-xilinx devices.
*/
# include "edif.h"
/* === BUF Devices === */
/* Buffer types of devices have the BUF_O and BUF_I pin
assignments. The BUF, INV, and certain specialized devices fit in
this category. */
extern edif_cell_t xilinx_cell_buf (edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_inv (edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib);
#define BUF_O 0
#define BUF_I 1
/* Only bufe and buft buffers have this input. */
#define BUF_T 2
/* === LUT Devices === */
/* Most Xilinx devices have LUT2/3/4 devices that take, respectively,
2, 3 or 4 inputs. All forms have a single bit output. Also, the
real behavior of the device will need to be specified by an INIT
parameter string. */
extern edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib);
#define LUT_O 0
#define LUT_I0 1
#define LUT_I1 2
#define LUT_I2 3
#define LUT_I3 4
/* === Flip-Flop Devices === */
/*
* These are flip-flops of various sort, but similar pinouts.
*/
extern edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib);
#define FDCE_Q 0
#define FDCE_C 1
#define FDCE_D 2
#define FDCE_CE 3
#define FDCE_CLR 4
#define FDCE_PRE 5
/* === Virtex/Virtex2 Carry Chain Logic === */
extern edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib);
#define MULT_AND_LO 0
#define MULT_AND_I0 1
#define MULT_AND_I1 2
extern edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib);
#define MUXCY_O 0
#define MUXCY_DI 1
#define MUXCY_CI 2
#define MUXCY_S 3
extern edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib);
#define XORCY_O 0
#define XORCY_CI 1
#define XORCY_LI 2
/* === Virtex/Virtex2 MUX devices */
extern edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_muxf7(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_muxf8(edif_xlibrary_t xlib);
#define MUXF_O 0
#define MUXF_I0 1
#define MUXF_I1 2
#define MUXF_S 3
/* === Inheritable Methods === */
extern void virtex_logic(ivl_net_logic_t net);
extern void virtex_generic_dff(ivl_lpm_t net);
extern void virtex_eq(ivl_lpm_t net);
extern void virtex_ge(ivl_lpm_t net);
extern void virtex_mux(ivl_lpm_t net);
extern void virtex_add(ivl_lpm_t net);
extern void xilinx_common_header(ivl_design_t des);
extern void xilinx_show_footer(ivl_design_t des);
extern void xilinx_show_scope(ivl_scope_t scope);
extern void xilinx_pad(ivl_signal_t, const char*str);
extern void xilinx_logic(ivl_net_logic_t net);
extern void xilinx_mux(ivl_lpm_t net);
extern void xilinx_add(ivl_lpm_t net);
extern void xilinx_shiftl(ivl_lpm_t net);
/*
* $Log: xilinx.h,v $
* Revision 1.1.2.1 2005/09/25 16:35:37 steve
* Add Xilinx virtex as a reference EDIF device.
*
*/
#endif

View File

@ -17,7 +17,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.16 2004/02/10 19:25:01 steve Exp $"
#ident "$Id: Makefile.in,v 1.16.2.2 2006/05/08 04:33:36 steve Exp $"
#
#
SHELL = /bin/sh
@ -39,6 +39,8 @@ CC = @CC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
MAN = @MAN@
PS2PDF = @PS2PDF@
CPPFLAGS = @ident_support@ -I.. -I$(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@
CFLAGS = -Wall @CFLAGS@
@ -83,13 +85,22 @@ clean:
distclean: clean
rm -f Makefile config.status config.log config.cache
rm -rf autom4te.cache
check: all
ifeq (@WIN32@,yes)
ifeq ($(MAN),none)
INSTALL_DOC = $(mandir)/man1/iverilog-fpga.1
else
ifeq (@PS2PDF@,none)
INSTALL_DOC = $(mandir)/man1/iverilog-fpga.1
else
INSTALL_DOC = $(prefix)/iverilog-fpga.pdf $(mandir)/man1/iverilog-fpga.1
INSTALL_DOCDIR = $(mandir)/man1
all: iverilog-fpga.pdf
endif
endif
INSTALL_DOCDIR = $(mandir)/man1
else
INSTALL_DOC = $(mandir)/man1/iverilog-fpga.1
INSTALL_DOCDIR = $(mandir)/man1

View File

@ -5,6 +5,8 @@ dnl Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
AC_CHECK_PROGS(MAN,man,none)
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
AC_CANONICAL_HOST
# $host

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: d-lpm.c,v 1.12 2004/10/04 01:10:56 steve Exp $"
#ident "$Id: d-lpm.c,v 1.12.2.1 2005/08/25 18:52:32 steve Exp $"
#endif
/*
@ -804,9 +804,19 @@ static void lpm_show_mult(ivl_lpm_t net)
static void lpm_show_constant(ivl_net_const_t net)
{
/* We only need one instance each of constant 0 and 1 bits. If
we need either of them, then create an instance reference and
save that reference here so that later needs for 0 or 1 can
find that the reference already lives and can be added to the
joint. */
static edif_cellref_t cell0_ref = 0;
static edif_cellref_t cell1_ref = 0;
static edif_joint_t cell0_jnt = 0;
static edif_joint_t cell1_jnt = 0;
edif_cell_t cell0 = edif_xlibrary_findcell(xlib, "cell0");
edif_cell_t cell1 = edif_xlibrary_findcell(xlib, "cell1");
edif_cellref_t ref0 = 0, ref1 = 0;
const char*bits;
unsigned idx;
@ -832,23 +842,26 @@ static void lpm_show_constant(ivl_net_const_t net)
bits = ivl_const_bits(net);
for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) {
if (bits[idx] == '1') {
if (ref1 == 0)
ref1 = edif_cellref_create(edf, cell1);
if (cell1_ref == 0) {
cell1_ref = edif_cellref_create(edf, cell1);
cell1_jnt = edif_joint_create(edf);
edif_add_to_joint(cell1_jnt, cell1_ref, 0);
}
} else {
if (ref0 == 0)
ref0 = edif_cellref_create(edf, cell0);
if (cell0_ref == 0) {
cell0_ref = edif_cellref_create(edf, cell0);
cell0_jnt = edif_joint_create(edf);
edif_add_to_joint(cell0_jnt, cell0_ref, 0);
}
}
}
for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) {
edif_joint_t jnt;
jnt = edif_joint_of_nexus(edf, ivl_const_pin(net,idx));
if (bits[idx] == '1')
edif_add_to_joint(jnt, ref1, 0);
edif_nexus_to_joint(edf, cell1_jnt, ivl_const_pin(net,idx));
else
edif_add_to_joint(jnt, ref0, 0);
edif_nexus_to_joint(edf, cell0_jnt, ivl_const_pin(net,idx));
}
}
@ -876,6 +889,9 @@ const struct device_s d_lpm_edif = {
/*
* $Log: d-lpm.c,v $
* Revision 1.12.2.1 2005/08/25 18:52:32 steve
* Join cell0 and cell1 instances in LPM target.
*
* Revision 1.12 2004/10/04 01:10:56 steve
* Clean up spurious trailing white space.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: edif.c,v 1.8 2003/09/03 23:34:09 steve Exp $"
#ident "$Id: edif.c,v 1.8.2.1 2005/08/27 22:29:30 steve Exp $"
#endif
# include "edif.h"
@ -393,6 +393,28 @@ edif_joint_t edif_joint_of_nexus(edif_t edf, ivl_nexus_t nex)
return jnt;
}
void edif_nexus_to_joint(edif_t edf, edif_joint_t jnt, ivl_nexus_t nex)
{
void*tmp = ivl_nexus_get_private(nex);
if (tmp != 0) {
/* There is a joint already on the nexus. Move all the
joint cells to the joint I'm joining to. */
edif_joint_t njnt = (edif_joint_t)tmp;
while (njnt->links) {
struct joint_cell_*cell = njnt->links;
njnt->links = cell->next;
cell->next = jnt->links;
jnt->links = cell;
}
/* Now njnt is dead, and should be removed from edif. */
/* Or we can ignore it as harmless. */
}
ivl_nexus_set_private(nex, jnt);
}
void edif_joint_rename(edif_joint_t jnt, const char*name)
{
assert(jnt->name == 0);
@ -617,6 +639,9 @@ void edif_print(FILE*fd, edif_t edf)
/*
* $Log: edif.c,v $
* Revision 1.8.2.1 2005/08/27 22:29:30 steve
* Back-port edif_nexus_to_joint from tgt-edif.
*
* Revision 1.8 2003/09/03 23:34:09 steve
* Support synchronous set of LPM_FF devices.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: edif.h,v 1.7 2003/09/03 23:34:09 steve Exp $"
#ident "$Id: edif.h,v 1.7.2.1 2005/08/27 22:29:31 steve Exp $"
#endif
# include <stdio.h>
@ -223,6 +223,8 @@ extern void edif_add_to_joint(edif_joint_t jnt,
edif_cellref_t cell,
unsigned port);
extern void edif_nexus_to_joint(edif_t edf, edif_joint_t jnt, ivl_nexus_t nex);
/*
* Print the entire design. This should only be done after the design
* is completely assembled.
@ -231,6 +233,9 @@ extern void edif_print(FILE*fd, edif_t design);
/*
* $Log: edif.h,v $
* Revision 1.7.2.1 2005/08/27 22:29:31 steve
* Back-port edif_nexus_to_joint from tgt-edif.
*
* Revision 1.7 2003/09/03 23:34:09 steve
* Support synchronous set of LPM_FF devices.
*

View File

@ -2,7 +2,7 @@
FPGA LOADABLE CODE GENERATOR FOR Icarus Verilog
Copyright 2001 Stephen Williams
$Id: fpga.txt,v 1.11 2003/08/07 05:17:34 steve Exp $
$Id: fpga.txt,v 1.11.2.1 2005/02/19 16:39:32 steve Exp $
The FPGA code generator supports a variety of FPGA devices, writing
XNF or EDIF depending on the target. You can select the architecture
@ -44,7 +44,7 @@ map to target gates if desired.
If this is selected, then the output is formatted as an XNF file,
suitable for most any type of device. The devices that it emits
are generic devices from the unified library. Some devices are macros,
youmay need to further resolve the generated XNF to get working
you may need to further resolve the generated XNF to get working
code for your part.
* arch=virtex
@ -188,6 +188,9 @@ Compile a single-file design with command line tools like so:
---
$Log: fpga.txt,v $
Revision 1.11.2.1 2005/02/19 16:39:32 steve
Spellig fixes.
Revision 1.11 2003/08/07 05:17:34 steve
Add arch=lpm to the documentation.

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