FPGARelated.com
Forums

low-level vs. high-level

Started by Evgeny Filatov September 11, 2015
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.
On 9/11/2015 2:18 PM, Evgeny Filatov wrote:
> 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.
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
Evgeny Filatov <e.v.filatov@ieee.org> wrote:
 
> 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.
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.
> 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?
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
On 9/11/2015 11:42 PM, glen herrmannsfeldt wrote:
> Evgeny Filatov <e.v.filatov@ieee.org> wrote: > >> 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. > > 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. > >> 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? > > 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.
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
rickman <gnuarm@gmail.com> wrote:

(snip)

>> I write structural verilog, or more recently structural VHDL.
> 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.
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
On 9/12/2015 9:33 AM, glen herrmannsfeldt wrote:
> rickman <gnuarm@gmail.com> wrote: > > (snip) > >>> I write structural verilog, or more recently structural VHDL. > >> 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. > > 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.
How else do people write their code?
> 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.
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
On Sat, 12 Sep 2015 03:42:00 +0000, glen herrmannsfeldt wrote:

> Evgeny Filatov <e.v.filatov@ieee.org> wrote: > >> 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. >
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
rickman <gnuarm@gmail.com> wrote:

(snip, I wrote0h)
>>>> I write structural verilog, or more recently structural VHDL.
>>> 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.
>> 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.
> How else do people write their code?
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.
>> 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.
> Sure, the two are very different. Behavioral code requires thinking and > analysis. Structural code is just a matter of wiring together blocks.
I consider continuous assignment part of structural, though it might have another name, and some logic goes in there.
> 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.
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.
> 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.
As far as I know, some people like the way it looks more like a software (sequential) programming language.
> 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.
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 <= X"0" when G='1' else A when S='0' else B; end architecture N157;
> 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.
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.
> Still, I think the high and mid-level modules will become rather verbose > with structural code.
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
Tim Wescott <tim@seemywebsite.com> wrote:
(snip)
>> Evgeny Filatov <e.v.filatov@ieee.org> wrote:
>>> 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.
> 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.
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
On 9/12/2015 2:00 PM, glen herrmannsfeldt wrote:
> rickman <gnuarm@gmail.com> wrote: > > (snip, I wrote0h) >>>>> I write structural verilog, or more recently structural VHDL. > >>>> 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. > >>> 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. > >> How else do people write their code? > > 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.
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.
>>> 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. > >> Sure, the two are very different. Behavioral code requires thinking and >> analysis. Structural code is just a matter of wiring together blocks. > > I consider continuous assignment part of structural, though it might > have another name, and some logic goes in there.
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.
>> 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. > > 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.
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.
> 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.
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.
>> 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. > > As far as I know, some people like the way it looks more like a > software (sequential) programming language.
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".
>> 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. > > 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.
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 <= LUT_Data when ('0' = PhaseSign) else - LUT_Data; --- or --- if ('0' = PhaseSign) then SineAmpWord <= LUT_Data; else SineAmpWord <= - LUT_Data; end if; A great reason for inferring this logic is because the tools may decide to skip the mux and use an adder with one input being a N bit bus of the control signal saving a bunch of logic. If I hardwired it as a mux it would not be as efficient and coding it this way I don't have to think about it. Then again the tools would likely optimize it either way. lol
> 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 <= X"0" when G='1' else A when S='0' else B; > end architecture N157;
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 <= a_input when 0, -- count/2 = 1 for this choice b_input when 1, c_input when 2, d_input when 3, e_input when others; END beh; Which is simpler and more clear? If you were coding something more complex, would you really want to code it by assembling pieces rather than just describing what it does? I had to use the schematic produced by synthesis to see what was done in the case of sel > 4 so I could code the behavioral logic the same.
>> 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. > > 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.
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.
>> Still, I think the high and mid-level modules will become rather verbose >> with structural code. > > 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.
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