FPGARelated.com
Forums

Structural vs Behavioral

Started by Hendra ●April 5, 2005
Both of the following 2 always blocks should synthesize to a decoder.

always @(address)
    case (address)
    2'b00 : row = 4'b0001;
    2'b01 : row = 4'b0010;
    2'b10 : row = 4'b0100;
    2'b11 : row = 4'b1000;
    endcase

always @(address)
  row = 2**address;

1. The first always block has 4 lines, and it will take much more lines
for wider address, but anybody who reads it notices immediately that
the code synthesizes to a decoder. The second always block only takes
one line, irrespective of the address' width. But it's harder to find
out what that line synthesize to. How do I know when to write my code
in "brute force" way (the first always code), or the "high level" way
(the second always block), which takes full advantage of HDLs with a
lot less lines? From all my previous projects, I always do the brute
force way. But sometimes I am wondering whether I am taking the right
approach. The brute force way seems like schematic, which can be done
as well by pulling components from the schematic library, which kind of
defeating the purpose of HDLs. On the other hand, if I use the high
level way, my code will take full advantage of HDLs, much shorter but
more difficult to debug. How do I know which one to choose?

3. When I do my projects, I always like to be able to see what my code
synthesize to (the schematic equivalent of the HDLs). That gives me
confident on the realibility of my projects. But should I forget about
the schematic equivalent and treat it just like C and as long as it
works then who cares about the schematic equivalent?

I need advise from professional engineers who have been in this field
for several years. I appreciate if you can help me making the decision.
Thank You!

Hendra

On 5 Apr 2005 03:32:57 -0700, "Hendra" <u1000393@email.sjsu.edu>
wrote:

>Both of the following 2 always blocks should synthesize to a decoder. > >always @(address) > case (address) > 2'b00 : row = 4'b0001; > 2'b01 : row = 4'b0010; > 2'b10 : row = 4'b0100; > 2'b11 : row = 4'b1000; > endcase > >always @(address) > row = 2**address;
[So, which is nicer...] Personally I like neither of these descriptions of a decoder; how about the following: always @(address) begin row = 0; row[address] = 1'b1; end This is likely to be efficient both for synthesis and for simulation, and (at least to me) it is crystal-clear that it represents a decoder, unlike "1<<address" or (worse) "2**address" which looks like a bizarre piece of arithmetic. Yet it is completely scalable to any size of vector. Now, I guess that you also have in mind some situations where it is much harder to find a representation in your code that meets all three of the criteria you nicely pointed out: - it should be easy to read - both its purpose, and the hardware structure it is intended to create, should be obvious - it should scale easily to different sized vectors, etc (no cut-and-paste!) - it should be effective, i.e. it should simulate efficiently and synthesise reliably to the logic you want As you have clearly seen, when you write an HDL design you are communicating on many levels: expressing your overall design intent, describing a specific implementation, and communicating your understanding to other human readers (who may be operating on only a subset of these levels). No-one ever said it was easy :-) You have, it seems to me, already taken the most important and most difficult step: you are asking yourself the right questions. All else is a combination of common sense, experience, and choosing something you are comfortable with. How about asking the following questions each time you write something... 1) Can I add comments to the code that will document it clearly enough so that I can understand it if I return to it a year later? 2) Could I explain it to my colleagues, without getting confused about my own intent? 3) What might I wish to change in the future? Have I done anything that would make that change unduly difficult? 4) Have I included a description of some unnecessary detail, that is not important to my purpose, and that the tools should sort out for themselves? 5) Could I have solved this problem using a pattern or style of coding that is already used elsewhere in my organisation? 6) Have I done something that is clever or ingenious, just for the sake of doing it? If so, how could I simplify it? My $0.02-worth: if you continue to challenge your own choices in the way you already are doing, then you won't go far wrong. -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL, Verilog, SystemC, Perl, Tcl/Tk, Verification, Project Services Doulos Ltd. Church Hatch, 22 Market Place, Ringwood, BH24 1AW, UK Tel: +44 (0)1425 471223 mail:jonathan.bromley@doulos.com Fax: +44 (0)1425 471573 Web: http://www.doulos.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated.
"Hendra" <u1000393@email.sjsu.edu> writes:

> Both of the following 2 always blocks should synthesize to a decoder. > > always @(address) > case (address) > 2'b00 : row = 4'b0001; > 2'b01 : row = 4'b0010; > 2'b10 : row = 4'b0100; > 2'b11 : row = 4'b1000; > endcase > > always @(address) > row = 2**address; > > defeating the purpose of HDLs. On the other hand, if I use the high > level way, my code will take full advantage of HDLs, much shorter but > more difficult to debug. How do I know which one to choose?
Well the third way juste requires a few extra bytes : always @(address) // that's a decoder row = 2**address; :-) MB -- Michel BILLAUD billaud@labri.fr LABRI-Universit&#4294967295; Bordeaux I tel 05 4000 6922 / 05 5684 5792 351, cours de la Lib&#4294967295;ration http://www.labri.fr/~billaud 33405 Talence (FRANCE)
Personally I would use

wire [3:0] row = 1<<address;  // This one-hot decode asserts row[address]

1) Succinct.
2) Commented
3) Why bother with an always block when an assign will do?


Hendra wrote:
> Both of the following 2 always blocks should synthesize to a decoder. > > always @(address) > case (address) > 2'b00 : row = 4'b0001; > 2'b01 : row = 4'b0010; > 2'b10 : row = 4'b0100; > 2'b11 : row = 4'b1000; > endcase > > always @(address) > row = 2**address; >
<snip> Not that this answers your question... but I believe both of these code fragments are behavorial code. Structural code instantiates components. The style of code I use is always based on the synthesis tool's guidelines doc. It's the first thing I read before writing any code.
On Tue, 05 Apr 2005 15:26:48 GMT, "John_H" 
<johnhandwork@mail.com> wrote:

>wire [3:0] row = 1<<address; // This one-hot decode asserts row[address] >1) Succinct. >2) Commented >3) Why bother with an always block when an assign will do?
Fascinating... I can't easily think of another four lines of text that could be as diametrically opposed to my own position as these. Point by point... Succinct - yes, but it needs a comment to make it easily comprehensible, thus dramatically reducing the (IMHO imaginary) benefit of brevity. Why is brevity good, for heavens' sake? Any half-decent piece of code will be at least 50% comment, so there is at the very most 50% saving to be made from brevity of code - and nothing, not even the tiniest thing, that compromises clarity and maintainability is worth that. Code is written once but read (and modified) often; saving a few keystrokes is not something that's worth chasing. Commented - yes, for sure. But the comments are just that, comments; they can get out-of-step with the code, and nobody gets to check. If, by writing somewhat more verbose code, I can "animate" the comments so that they are part of the code's functionality, then I don't have that risk. In general I am deeply distrustful of comments that describe the behaviour of procedural code, which tends to be almost self-evident to anyone skilled in the language; the teacher in me still comes out in a cold sweat at the sight of this vacuity: i = i + 1; // increment i So, let's have the comments as far as possible embedded in the code itself. Intriguingly, the most useful part of your commentary, where you say "assert row[address]", could easily be a piece of procedural Verilog (see my earlier post). Note, by the way, that assertions provide an even better way to add "animated comments" that *are* checked by tools. An assertion could easily check for one-hot-ness of the output, for example. Why bother with always? - Because it gives me a lot more room to manoeuvre if I later decide I need to change something. Especially in Verilog, where the change from "assign" to "always" also impacts the declaration of various things, I lean towards using "always" right from the start so that there's less to change later. Of course there are exceptions: some places you have little choice but to use assign (three-state drivers, etc); certain patterns of glue logic, like fixes for the polarity of strobe signals, are nicer done as assigns. But any logic with some real functionality behind it IMHO belongs in a procedural block. These are emphatically my own opinions and I am very much aware that many skilled people will profoundly disagree with me. I'm sure there is a place for both points of view, and for many in between. Just so long as everyone is aware that the choice is not obvious :-) -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL, Verilog, SystemC, Perl, Tcl/Tk, Verification, Project Services Doulos Ltd. Church Hatch, 22 Market Place, Ringwood, BH24 1AW, UK Tel: +44 (0)1425 471223 mail:jonathan.bromley@doulos.com Fax: +44 (0)1425 471573 Web: http://www.doulos.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated.
I'd have to vote with John_H here but I know many won't.

wire [3:0] row = 1<<address; // about as good as it gets

When  I see code that describes an obvious TTL nobrainer structure
using more than a few lines of code I start to wonder, are we boosting
line count or being succinct.

If it can be done in a few chars or 1 line why use any more.

Even more so giving every minor structure it own always begin .. end or
assign {} when a lot of related assignments can be bumped into 1 larger
 always / assign cluster for the overall function. Same as putting tiny
pieces of related logic on separate schematics sheets.

We dont usually see C programs with a set of {} around each and every
statement, only logically related code blocks. Same as over (())
expressions, my C VC6 compiler always nags me because it assume I can't
remember precedence rules for <<& bit extracting so I have to put in
more () than I need to keep warnings down.

But JB is right, always question evrything you do to see if there are
better ways to do it.

The Doug Smith book gives out pretty good examples of this sort of
thing too in several languages for ASICs & FPGAs all meant to
synthesize well with the schematics.

My 2c from an old APL kind of guy

johnjakson at usa dot com

I could also say it wasn't that long ago that I would have written

DEC4_1 u0 (.addr(i), .out(o)); // or whatever the std cell was called

Now that synthesis has fully taken over except at the very top end of
the speed curve, its not so necessary, only on interesting block level.

Although instancing of blocks is usually considered structural or
schematic thinking, you can then put anything at all into the module
that describes that it even the original case statement as the visual
clutter from it is now elsewhere.

There is another way to have it both ways and that is to use a folding
text editor, click on the 1 liner and see the the 1 or 5 or 100 lines
it represents. Pretty much a schematic thing to do to when you could
push down into sub sheets.

Does anyone actually use such a thing, recomendations esp Windows,

I half suspect Emacs can do it but never took to it.

johnjakson at usa dot com

"JJ" <johnjakson@yahoo.com> writes:

<snip>
> There is another way to have it both ways and that is to use a folding > text editor, click on the 1 liner and see the the 1 or 5 or 100 lines > it represents. Pretty much a schematic thing to do to when you could > push down into sub sheets. > > Does anyone actually use such a thing, recomendations esp Windows, >
I used to use CodeWright - dunno if it even still exists, but that did folding IIRC.
> I half suspect Emacs can do it but never took to it. >
:-) Yes, I use folding-mode a lot in my VHDL - the emacs VHDL-mode is the reason I finally took the plunge with emacs! I don't think the verilog-mode is as fully-featured - so maybe it won't suit you so much... Cheers, Martin -- martin.j.thompson@trw.com TRW Conekt, Solihull, UK http://www.trw.com/conekt
On Tue, 05 Apr 2005 09:36:12 -0700, JJ wrote:

> I'd have to vote with John_H here but I know many won't. > > wire [3:0] row = 1<<address; // about as good as it gets > > When I see code that describes an obvious TTL nobrainer structure > using more than a few lines of code I start to wonder, are we boosting > line count or being succinct. > > If it can be done in a few chars or 1 line why use any more. > > Even more so giving every minor structure it own always begin .. end or > assign {} when a lot of related assignments can be bumped into 1 larger > always / assign cluster for the overall function. Same as putting tiny > pieces of related logic on separate schematics sheets. > > We dont usually see C programs with a set of {} around each and every > statement, only logically related code blocks. Same as over (()) > expressions, my C VC6 compiler always nags me because it assume I can't > remember precedence rules for <<& bit extracting so I have to put in > more () than I need to keep warnings down. >
I'd say that a compiler that warns about unnecessary parenthesis in expressions with bit manipulation is broken. It is far more helpful for the compiler to warn about not having enough parenthesis to make the meaning clear - gcc does this, with appropriate flags. Code should be written to be easily read and easily understood - not to be typed with the minimal number of characters. When C was first used, minimal character count was a priority - and the results of that language design decision have been felt ever since. Writing long-winded or excessively commented code is just as bad as overly terse and compact code, however.