C++/Java Generators vs. Synthesizers

Home

CPUs vs. FPGAs >>
<< CNets and Datapaths

Usenet Postings
  By Subject
  By Date

FPGA CPUs
  Why FPGA CPUs?
  Homebuilt processors
  Altera, Xilinx Announce
  Soft cores
  Porting lcc
  32-bit RISC CPU
  Superscalar FPGA CPUs
  Java processors
  Forth processors
  Reimplementing Alto
  Transputers
  FPGA CPU Speeds
  Synthesized CPUs
  Register files
  Register files (2)
  Floating point
  Using block RAM
  Flex10K CPUs
  Flex10KE CPUs

Multiprocessors
  Multis and fast unis
  Inner loop datapaths
  Supercomputers

Systems-on-a-Chip
  SoC On-Chip Buses
  On-chip Memory
  VGA controller
  Small footprints

CNets
  CNets and Datapaths
  Generators vs. synthesis

FPGAs vs. Processors
  CPUs vs. FPGAs
  Emulating FPGAs
  FPGAs as coprocessors
  Regexps in FPGAs
  Life in an FPGA
  Maximum element

Miscellaneous
  Floorplanning
  Pushing on a rope
  Virtex speculation
  Rambus for FPGAs
  3-D rendering
  LFSR Design
 

Google SiteSearch
Newsgroups: comp.arch.fpga
Subject: C++/Java generators vs. synthesizers
Date: Tue, 11 Jul 2000 21:12:06 -0700

Whenever we have this discussion, which does recur, there is one important
distinction that needs to be made: in both C++ and Java, it is possible to
write both *generators* as well as *synthesis* systems. They are quite
different beasts.  Some examples:

1. Netlist generators (explicit hardware specification systems), such as
* C++: PamDC [1], PAM-Blox [2], CNets [3],
* Java: Chu et al (Berkeley) 'OO Circuit Generator in Java' [4], JHDL [5]
* Others: Lola/Trianus/Hades [6]

2. HLL synthesis (behavioral compilers / hardware inference systems), such
as
* C/C-like: Napa-C [7], Streams-C [8], Handel-C [9], Leong's lcc-VHDL system
[10], 'Tsukuba' C-HDL compiler [11]
* Java: Galadriel/Nenya [12], LavaLogic Forge [13]

(Apologies if I have miscategorized or overlooked your favorite.) And then
there's SystemC [14] and others, which I think support both paradigms.

Comparing generators to synthesizers is just like comparing schematics to
HDL synthesis. In the former, you have explicit control over what you get,
and in some cases, how it is technology mapped and placed.  But then you
*do* have to explicitly instantiate everything. In a synthesis system, you
have tools that do that for you, but tend to achieve inefficient results
quickly.

In my opinion, generators can have all the 'explicitness' advantages of
schematics, plus text representation, HLL integration and programmability,
with none of the disadvantages. There is just a critical mass adoption
issue -- in lieu of one dominant approach, there is no opportunity for reuse
across existing experimental systems and none have seemed to gain traction.

HLL synthesis, I'm ambivalent about. I hate wasting hardware, but I
understand others are more sanguine about that. I wonder just how much of an
improvement over HDLs they are, given you often don't get the full HLL
semantics, and apparently you often need to add pragmas and directives to
help synthesis make the right things parallel and/or sequential, put the
right data in registers or internal RAM or external RAM, etc.

Just as C compilers sometimes outperform assembly hackers, it is (remotely)
possible that someday these can generate designs that approach a careful
schematic design? Are they a revolutionary development that will make it
easy for your average C/Java programmer to design hardware? Will they let
you push a button and get hardware from a dusty deck C or Java library?  I
doubt it. Software design concerns are quite different from hardware design
concerns. Also, I believe that a good C programmer can pick up Verilog and
Verilog concepts about as easily as they can learn the additional keywords
and directives and restrictions necessary to infer comparable hardware with
an HLL synthesis system.

Perhaps someone who uses and prefers HLL synthesis can share their
experiences.

Jan Gray
Gray Research LLC

References

[1] http://www.research.digital.com/SRC/pamette/Software.html)
[2] http://umunhum.stanford.edu/PAM-Blox/
[3] http://www.fpgacpu.org/usenet/cnets_datapath.html
[4] http://brass.cs.berkeley.edu/documents/Generators_FCCM98.html
[5] http://www.jhdl.org/
[6] http://www.cs.inf.ethz.ch/projects/lola/trianus/
[7] FCCM98
[8] Gokhale et all, FCCM00, also e.g.
http://www.arpa.gov/ito/psum1998/F282-0.html
[9] http://www.embeddedsol.com/technology/info_sheets/info_sheet_01.htm
[10] "Automatic Floating to Fixed Point Translation and its Application to
Post-Rendering 3D Warping", FCCM99,
http://www.cse.cuhk.edu.hk/~phwl/papers/fccm99_fixed.ps.gz
[11] Maruyama, FCCM00
[12] http://www.acm.org/crossroads/xrds5-3/rcconcept.html
[13] http://www.lavalogic.com/product/wp_forge.html


Newsgroups: comp.arch.fpga
Subject: Re: C++/Java generators vs. synthesizers
Date: Wed, 12 Jul 2000 14:14:20 -0700

"Nicholas C. Weaver"  wrote in message
> C++ doesn't even attempt metalinguistic abstractions, and
> Java's (the Reflection interface) is almost hopelessly crippled by
> security restrictions.  And Java doesn't have good overloading
> mechanisms of operators, which would make the syntax much cleaner for
> many operations.

I have designed working and prototype/sketch generators in C++ and Java and
I have found exactly this.  However, in practice, I think the benefits of
C++ operator overloading are worth the hassle of "introducing' C++'s member
data to themselves" with lightweight _ macros (as shown below):

(This is not CNets, just a sketch of some newer ideas since:)

// mymuxes.h -- user application -- some muxes:
#include "module.h"

module(Mux2) { // define a 2-1 mux
  In a, b, sel;
  Out o;
  implement(Mux2) _4(a,b,sel,o) as { o = a&~sel | b&sel; /*=> FMAP*/ }
};

module(Mux4) { // define a 4-1 mux as a composition of three 2-1 muxes
  In a, b, c, d, sel1, sel2;
  Out o;
  Net o1, o2;
  Mux2 m1, m2, m3;
  implement(Mux4) _7(a,b,c,d,sel1,sel2,o), _5(o1,o2,m1,m2,m3) as {
    m1.a(a).b(b).sel(sel1).o(o1).rloc(0,0);
    m2.a(c).b(d).sel(sel1).o(o2).rloc(0,0);
    m3.a(o1).b(o2).sel(sel2).o(o).rloc(0,1);
  }
};


// module.h -- standard module generator header
struct Module;
extern stack modules; // currently 'open' modules being defined

struct Net { ... };

struct Entity : Net {
  string name;
  Entity(string name) { this->name = name; modules.top()->addEntity(name,
this); }
  Entity& connect(Net& net) { ... }
}

struct Module : Entity {
  map members;
  Module(string name) : Entity(name) { modules.push(this); }
  Module& connect(string name, Net& net) { members.at(name)->connect(net);
return *this; }
  Module& rloc(int r, int c) { ... return *this; }
  Module& p(Net& net) { return connect("p", net); }
#define p(port) Module& port(Net& net) { return connect(#port, net); }
#include "stdports.h"
#include "userports.h"
#undef p
};
struct LastMember {
  LastMember() { modules.pop(); }
};
// reflection support
#define _(member) member(member)
#define _1(a) _(a)
#define _2(a,b) _(a),_b()
#define _3(a,b,c) _(a),_(b),_(c)
#define _4(a,b,c,d) _(a),_(b),_(c),_(d)
#define _5(a,b,c,d,e) _(a),_(b),_(c),_(d),_(e)
#define _6(a,b,c,d,e,f) _(a),_(b),_(c),_(d),_(e),_(f)
#define _7(a,b,c,d,e,f,g) _(a),_(b),_(c),_(d),_(e),_(f),_(g)
#define _8(a,b,c,d,e,f,g,h) _(a),_(b),_(c),_(d),_(e),_(f),_(g),_(h)
#define _9(a,b,c,d,e,f,g,h,i) _(a),_(b),_(c),_(d),_(e),_(f),_(g),_(h),_(i)
#define _10(a,b,c,d,e,f,g,h,i,j)
_(a),_(b),_(c),_(d),_(e),_(f),_(g),_(h),_(i),_(j)
#define _11(a,b,c,d,e,f,g,h,i,j,k)
_(a),_(b),_(c),_(d),_(e),_(f),_(g),_(h),_(i),_(j),_(k)
#define _12(a,b,c,d,e,f,g,h,i,j,k,l)
_(a),_(b),_(c),_(d),_(e),_(f),_(g),_(h),_(i),_(j),_(k),_(l)
#define module(M) struct M : public Module
#define implement(M) LastMember __end; M(string name) : Module(name),
#define as,__end()


// stdports.h -- standard port names
p(a) p(b) ... p(o) p(q) ... p(z)


// userports.h -- user application port names:
p(m1) p(m2) p(m3)
p(o1) p(o2)
p(sel) p(sel1) p(sel2) p(sel3)


That's the sketch.  This may not mean a lot to most of you, but may mean
something to Nicholas. :-)  Does it work?  I don't know.

Jan Gray
Gray Research LLC

Copyright © 2000, Gray Research LLC. All rights reserved.
Last updated: Feb 03 2001