low-level vs. high-level

Hi,

I use graphical high-level tools to design DSP stuff and generate RTL for it. It works for me, but I started to suspect that it is more efficient to write RTL in HDL languages instead.

Is there any general rule of thumb for how much is sacrificed (in terms of area / performance) by using high-level tools, as opposed to writing RTL manually in VHDL/Verilog?

Regards, Evgeny.

Reply to
Evgeny Filatov
Loading thread data ...

If you are using a good optimizing synthesis tool chain, the difference may not be very large. I used some Mathcad generated RTL on a project, and by the time the synthesis tool was done, it was as tight as I could have gotten it by hand.

Regards, BobH

Reply to
BobH

I am not sure what there is in high-level tools.

If you mean schematic capture, I find it a lot of work for many actual problems.

But it might be that some people are more visual than others, and find it hard to read and understand HDL.

Most of the designs I work on are pretty low level, but if you write the appropriate modules (or entities), you should be able to make it look right in HDL. Write modules for high-level DSP blocks and wire them up with HDL.

I write structural verilog, or more recently structural VHDL.

-- glen

Reply to
glen herrmannsfeldt

I'm not sure what you mean by that. Everyone writes structural HDL. But they also write the code in the blocks that gets connected by the structural HDL. Don't you? That is the hard part.

--

Rick
Reply to
rickman

(snip)

I write a very small part of my verilog in always blocks, or vhdl in process blocks, and usually in leaf modules/entities.

As well as I know, not everyone does that.

The verilog books that I know make a bigger distinction between behavioral and structural than the VHDL books, but both have it.

Many always/process blocks have one statement in them, though sometimes two or three. A loadable counter with reset might go in one.

-- glen

Reply to
glen herrmannsfeldt

How else do people write their code?

Sure, the two are very different. Behavioral code requires thinking and analysis. Structural code is just a matter of wiring together blocks.

I think maybe what you are saying is that you only write behavioral code for very small logical functions and create more complex functions by wiring them together. This would be analogous to designing a board using SSI and MSI logic while others write behavioral modules more like LSI and and VLSI, only using the structural code for the greatly reduced interconnect.

The main reason I can see for writing code using less structural and more behavioral code is the greatly reduced code required. But then I'm not sure it would be greatly reduced. I'm just familiar with interconnecting larger blocks where structural code is a PITA because of the verbosity. Each signal has to be declared in the higher module, listed in the instantiation and declared as I/O in the lower module. This can be so tedious that I have rather lengthy regular expressions I keep in my code to automagically convert between them.

Actually, I realize using structural code at the lower levels would be

*very* verbose because none of the higher level structural code is reduced. So writing high and mid-level modules in structural code would add lots of verbiage.

Once a process is defined, it can add another register with just three rather simple lines of code. Declare the signal, initialize the signal and assign the signal. Even creating a new process only adds two more lines. Structural code for this requires at least as many lines of code along with any generics and the common signals like reset and clocks. Well, I count a lot of lines because I write in a spread out manner with each I/O signal on it's own line. If you come from the Verilog world your style may vary.

Still, I think the high and mid-level modules will become rather verbose with structural code.

--

Rick
Reply to
rickman

I'm assuming he means that he draws up a block diagram in Simulink and then pushes a button (well, maybe after lots of simulation and analysis).

But I'm just assuming.

--
www.wescottdesign.com
Reply to
Tim Wescott

(snip, I wrote0h)

Well, in verilog you can write combinatorial logic with either continuous assignment not in an always block, or a behavioral assignment (that is what the book nearby seems to call it) in an always block. Two different ways to say the same thing.

The only way I make registers and latches in verilog is with an always block. It might be that it can be done in VHDL without a process block, but so far I use one, such that it looks similar to the matching verilog.

I consider continuous assignment part of structural, though it might have another name, and some logic goes in there.

Some can be written about the same either way. When I have a choice between verilog continuous assignment and behavioral assignment, I choose the former, others might choose the latter.

I usually put registers into their own module, even if that is the only thing in the module.

One that I am working on now is exactly taking a design in SSI and MSI and writing it in VHDL. The SSI (gates) go into assignment statements with the appropriate logical operations. MSI (anything more complicated than just gates) into a module. I can verify the operation of the module once, and use it many times.

As far as I know, some people like the way it looks more like a software (sequential) programming language.

Well, for example, I might write a multiplexer in a module, nice combinatorial logic with no registers, then use that module wherever I need a multiplexer, instead of rewriting one each time.

Internally, that module will use either the verilog conditional operator or VHDL WHEN operator. (Being use to C, I find the WHEN syntax a little strange, but it doesn't take long to get used to.)

I suspect others will build a multiplexer using behavioral if statements in either language.

OK, here is a multiplexer in VHDL:

library IEEE; use IEEE.std_logic_1164.all;

entity N157 is port ( Y : out std_logic_vector(3 downto 0); A, B : in std_logic_vector(3 downto 0); S, G: std_logic); end entity N157;

architecture N157 of N157 is begin Y Once a process is defined, it can add another register with just three

If it fits reasonably, I put a whole module/entity instatiation on one line. I stay within 80 characters (for one, so that they print nicely), so some will take more lines. Maybe that is from using verilog first.

My early verilog was systolic arrays, with repeated blocks of fairly simple code. The mid-level module fit on one or two pages, matching fairly closely the register transfer logic that one might write. Lower level were registers, adders, comparators, and multiplexers. Top level instantiated some number of the unit cell in a linear array.

-- glen

Reply to
glen herrmannsfeldt

I do remember using schematic drawing tools, but most often found it took a lot of work drawing lines, making sure that they didn't overlap what they weren't supposed to, and otherwise getting it right.

But I can write some lines of verilog or VHDL and not have to worry about such lines overlapping. Match up signal names and everything works the way it is supposed to.

But I suppose something like simulink isn't so bad. Generate the VHDL or verilog, look at it, and see if it looks right.

-- glen

Reply to
glen herrmannsfeldt

Yes, if you want, you can describe a FF in a continuous assignment in VHDL, but it is very unconventional and not very malleable.

I'm not sure why you are drawing some of the distinctions you do. I have never seen anyone consider continuous assignments to be "structural" HDL. Rather complex logic can be defined that way although I think most logic ends up in processes or the equivalent.

I only consider instantiations to be structural. Continuous assignments have several logical constructs which will infer logic and are often used that way. It is actually seldom that I use continuous assignments for structure since the connections are made in the component instantiations. Why would I want to connect two wires with an assignment unless there was something very odd going on like one wire into a module connected to two wires going out? I don't know I have ever done that.

Not sure why that matters. If it generates logic, it is not structural. I think we have a *big* difference in definitions. Behavioral does not imply any type of assignment to me. It is a method of designing logic by describing how the logic works rather than describing how it is constructed. Both concurrent and sequential coding is used for behavioral design.

Purely structural design would use instantiation only without inference by any statement type other than within the primitive units.

Of course my designs are never purely behavioral without use of module instantiation. It is easier to test a design in pieces, then glue the pieces together and test again. I think our disagreement is how far down the modules are divided. My typical module size is a couple dozen to a hundred or so lines. Although the really large ones are the top level gluing it all together with structural code. One of my smaller top level modules is over 600 lines of glue. Not hard to get right using the tools that let me copy and paste with regular expression conversions. Errors creep in when changes are made.

MSI is a very basic functional block. If you are using this very often you likely are working at a very low level.

The point is that it is not rocket science to code a shift register or counter. There is very little value in being able to say you have a verified counter module. Not much different than saying you have a verified multiplexor module which you say you do in continuous assignments.

In the end, using such MSI components can be as error prone as writing them from scratch. I avoid most errors in behavioral code by pulling up an existing file and copying an arbitrary process for a registered function and then editing the code. It also reduces the tedium. Then I can focus on the specifics of what this function needs to do other than be a register.

Not sure what you mean by this. Only the guts of processes, procedures and functions look and feel like a sequential language. I think we may be talking about different things because you include continuous assignments as "structural".

Yeah, that is the level of design that should be like falling off a log. It is a one liner in a continuous assignment, five lines in a process with two of them being ELSE and END IF;

Here is an example...

SineAmpWord

This is a terrible multiplexor module in VHDL. It is exactly 4 bits wide when it could have been made N bits wide. Also it only works for SLV data type when the example I use above will work for any types available. BTW, what's with the name N157? Wouldn't it be better to use something more descriptive? Otherwise, notice that all the work is done in one line. Why go to all the trouble of the above when you only need the one line?

Here is an example of a 5 to 1 mux by instantiation from a VHDL lecture.

--5:1 mux, 1 bit wide LIBRARY ieee; USE ieee.std_logic_1164.ALL; LIBRARY adk; USE adk.all; ENTITY mux5_1_1wide IS PORT( a_input : IN STD_LOGIC; --input a b_input : IN STD_LOGIC; --input b c_input : IN STD_LOGIC; --input c d_input : IN STD_LOGIC; --input d e_input : IN STD_LOGIC; --input e sel : IN STD_LOGIC_VECTOR(2 DOWNTO 0); --sel input z_out : OUT STD_LOGIC --data out ); END mux5_1_1wide; ARCHITECTURE beh OF mux5_1_1wide IS SIGNAL temp0, temp1, temp2, temp3 : STD_LOGIC; COMPONENT mux21 PORT( a0,a1,s0 : IN STD_LOGIC; y : OUT STD_LOGIC); END COMPONENT; COMPONENT inv01 PORT( a : IN STD_LOGIC; y : OUT STD_LOGIC); END COMPONENT; BEGIN U1 : mux21 PORT MAP(a0 => a_input, a1 => b_input, s0 => sel(0), y => temp0); U2 : mux21 PORT MAP(a0 => c_input, a1 => d_input, s0 => sel(0), y => temp1); U3 : mux21 PORT MAP(a0 => temp0, a1 => temp1, s0 => sel(1), y => temp2); U4 : mux21 PORT MAP(a0 => temp2, a1 => e_input, s0 => sel(2), y => temp3); U5 : inv01 PORT MAP(a => temp3, y => z_out); END beh;

Using behavioral descriptions.

--5:1 mux, 1 bit wide LIBRARY ieee; USE ieee.std_logic_1164.ALL; LIBRARY adk; USE adk.all; ENTITY mux5_1_1wide IS PORT( a_input : IN STD_LOGIC; --input a b_input : IN STD_LOGIC; --input b c_input : IN STD_LOGIC; --input c d_input : IN STD_LOGIC; --input d e_input : IN STD_LOGIC; --input e sel : IN STD_LOGIC_VECTOR(2 DOWNTO 0); --sel input z_out : OUT STD_LOGIC --data out ); END mux5_1_1wide; ARCHITECTURE beh OF mux5_1_1wide IS BEGIN with sel select z_out 4 so I could code the behavioral logic the same.

To do that you need to use positional association which is error prone. Not a big deal for small entities, but harder to get right for large ones with lots of I/O. I *always* use named association to prevent difficult to find errors.

There will be some designs that suit instantiation well. I remember a frequent poster here with a company specializing in high speed design in Xilinx devices. He used hierarchical schematic design since it gave him complete control over both the logic and placement via attributes attached to the various symbols. When the rest of the world was moving to HDL, he resisted until he was shown how he could do exactly the same things in VHDL. He never looked back. Clearly structural HDL was the way to go for him.

--

Rick
Reply to
rickman

rickman wrote: (snip, I wrote)

(snip, I wrote)

OK, it seems that the book I have calls the continuous assignment form data-flow model. (snip)

A lot of my VHDL assignments are putting together or taking apart vectors. It seems that VHDL feature is too new. So I have:

y29 > Some can be written about the same either way. When I have a

I suppose, but structural plus continuous assignment takes too long to write.

I suppose, but I do know people who write mostly behavioral, with one big process block in each entity.

If the design is already written in such blocks, it works well.

(snip)

OK, but continuous assignment isn't behavioral either.

Behavioral has its own assignment.

The tools are pretty good. Sometimes a small mistake and half the logic gets optimized away.

It is the logic of the 74157.

If the logic is already written using such blocks, it is much easier to write VHDL from those blocks, and then verify that they look like the original design.

Also, as well as I know it, that isn't behavioral.

For behavioral verilog it would look something like:

always @(*) begin if (sel=0) then z_out nicely), so some will take more lines. Maybe that is from using

-- glen

Reply to
glen herrmannsfeldt

"Data-flow" is a completely unrelated concept from my experience. I have no idea what they mean by that. Verilog jargon perhaps? I am not conversant in Verilog as much as VHDL where they are called concurrent assignments.

There is no difference between a concurrent assignment and a process with just one assignment and a sensitivity list with all input signals. In general, a process can have many assignments including variable vs. signals and the sensitivity list can include just a subset such as (clk, rst) for a clocked process.

I looked up "Verilog data flow" and found no real definition of it and found it used in different ways on each page. One page refers to "structural data flow modelling" and "Behavioral data flow modelling".

I think the term "data flow" should be ignored in this context and just "structural" and "behavioral" should be used.

In my book (the one in my head) "behavioral" includes any inference of logic while "structural" is instantiated.

To muddy the waters a bit, I see the term "RTL" (register transfer level) which is behavioral, but implies the level of abstraction does not rise above describing specific registers and logic.

I am pretty sure you can use (a, b, c, d) in the component port map. But there are some specific details on this and I haven't done much with any HDL for a while so I've forgotten the finer points. (a, b, c, d) is called and aggregate in VHDL.

I don't follow. I thought you said that was what you do!

Yeah, I find one process per entity to be a bit awkward. I use multiple processes to organize my thoughts. So each process will have a functional purpose. Some small like a resynchronizer with just two FFs, or some large with logic that is more than one register, but with complex interaction which are awkward to break apart. Personal preference. I just don't like very large processes so that it becomes hard to see what is going on.

I don't know what this means. Behavioral isn't part of an HDL language. It refers to how you write your code. By instantiating low level primitives you are defining your design by the gates used (even if the tools will optimize that as it sees fit). Behavioral means you describe what the logic does. You can only do structural using instantiation. If you use concurrent assignments or processes to do anything other than connect wires you are inferring logic based on a description of what it does, not the gates it is made of.

I don't understand. If the blocks were there, you don't need to write anything. The above example illustrates how simpler behavioral code is than structural code once you are working with higher levels of logic. This is not even a very high level. Try structurally coding a UART with full handshake controls and flags. A UART is a very simple IP block. Then imagine coding a USB controller.

Both of these are behavioral. You are describing how the circuit behaves, not the gates used to implement it. The only difference is one is continuous and the other is sequential.

Someone is giving you bad information. I hope this helps some.

--

Rick
Reply to
rickman

(snip, I wrote)

It seems that this changed over the years.

As for Xilinx ISE, it works in the port for some devices, but not others. Doesn't make much sense, but they use a different VHDL parser for Spartan 3E and for Spartan 6. One allows it, one doesn't.

Even newer in VHDL is the ability to do that in an output port. (or the left side of an assignment) like you could do in verilog for many years.

But if can get a little ugly if not done carefully.

-- glen

Reply to
glen herrmannsfeldt

(snip)

(snip)

I mean the name of it takes too long to write. That is why I call it structural, even though it is more. (snip, I wrote)

Behavioral model is inside verilog always blocks, and VHDL process blocks, and yes it describes what the logic does. (snip, I wrote)

I am converting an existing design, made with TTL and such, into VHDL. By following the TTL MSI blocks, I can do that with minimal thinking and minimal mistakes. I don't have to understand what the logic does, just be sure that what I write does the same thing as the original. (snip, I wrote)

Well, I pretty much learned verilog from the Thomas and Moorby book, and if you claim that they are wrong, many people will disagree.

They don't make it so obvious, but early on they have an example of a 16 bit counter in structural model, which does include a continuous assignment to indicate when the counter is about to overflow.

Later on, they have a behavioral model counter, which doesn't use continuous assignment, but with all the logic inside an always block. The actual block looks something like:

always begin @(negedge clock) #10 value = value + 1; if(value==15) begin altFifteen=1; fifteen=1; end else begin altFifteen=0; fifteen=0; end end endmodule

They call it behavioral model, and so do I.

Note, for example, that the assignment are not continuous, but only done with the appropriate if condition.

Well, read chapter 1 of Thomas and Moorby, and see what you think qualifies as behavioral, or not behavioral, logic.

-- glen

Reply to
glen herrmannsfeldt

Tim is correct. An example (GPS C/A stuff):

formatting link

I just suck at writing in VHDL/verilog. Should practice more.

Regards, Evgeny.

Reply to
Evgeny Filatov

(snip, I wrote)

(snip)

OK, the tools are surprisingly good at doing what needs to be done.

If the problem is well described at the higher level, it is probably fine.

If you need the highest speed, though, you might need to pipeline it, and that might not be so easy from the high level representation.

If it is fast enough, and the high-level logic mostly does what you want, you might not need to worry.

-- glen

Reply to
glen herrmannsfeldt

Ok, but that means our conversation has mostly been one large misunderstanding...

I think what you mean is you don't use processes other than for describing specific registers or something like that.

There is the core of our misunderstanding. No one else I have found uses that definition of "behavioral".

Sure, that is ideal for structural code. Duplicating something similar to a schematic. But your definitions of the TTL components is most likely to be behavioral. It is not too hard to design a 74x138 with gates. The TI data sheet shows a schematic with 25 gates in it. Much easier to do it with a simple with select statement inside an if as part of a process.

Ok, but you really should read a bit more widely. You will find the definition of "behavioral" has nothing to do with always blocks or processes. It means the code is describing the behavior of the logic in contrast to "structural" which is showing how blocks of logic are wired together. "Continuous" assignments describe the behavior of the signal they are assigned. They are equivalent to processes in all ways.

You are confusing "continuous" with non-behavioral. The assignments work the same way regardless.

I can't speak for sure about Verilog, but I expect it works the same as VHDL. "Continuous" assignments are the same as processes which have all inputs to the assignment in the sensitivity list. This means the process (or continuous assignment) does not run until one of the inputs changes. Then the assignments are evaluated to produce an output which may or may not have changed.

The fact that an IF is used in a process does not mean it is not "continuous" in any mechanical sense. This is just a description of a logic function. The signals in the IF statement are either assigned one of two possible values (the THEN clause or the ELSE clause) or if no assignment is included in one that infers a register or latch depending on the outer logic (such as an IF clock or @(negedge clock)).

process (PhaseSign, LUT_Data) begin if ('0' = PhaseSign) then SineAmpWord

Reply to
rickman

Certainly VHDL can be verbose and it can present stumbling blocks to a newbie. I came from a world of schematics, so it isn't hard to impress me considering the huge improvement in productivity.

If I ever find a good Verilog book, I will get more proficient with it.

--

Rick
Reply to
rickman

Well, at least in VHDL, there is structural and behavioral. Behavioral VHDL looks like

a
Reply to
Jon Elson

The confusion seems to come from the fact that a small number of Verilog texts and university materials use the terms for something other than what most of us use them for. Seems some use "behavioral" for code written in always blocks and "structural" for all other code.

Most references use the term "behavioral" as you seem to be using it, for code that largely describes the behavior in code that is then used to infer the logic to implement the behavior. Structural code would be purely instantiating logic entities that exist.

What ever the case, I think Glen and I understand each other. Glen doesn't like to use always blocks or processes and I am happy using them while minimizing my use of instantiation.

--

Rick
Reply to
rickman

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.