| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#1
| |||
| |||
| OK, so I tried the following synthesis example - various declarations omitted to save space. I have been able to try this on five different synthesis tools, spanning the whole range of cost and FPGA-vs-ASIC. The results surprised me a little - it's a long time since I did such a complete survey. ~~~~~~~ Form 1: Clocked process, with combinational output logic outside the usual clocked if..else...endif block. ~~~~~~~ process(clock, reset) variable count: unsigned(7 downto 0); begin -- 8-bit counter, clocked with async reset if reset = '1' then count := (others => '0'); elsif rising_edge(clock) then count := count + 1; end if; -- Combinational logic q <= std_logic_vector(count); msb <= count(7); if count = (count'range => '1') then tc <= '1'; else tc <= '0'; end if; end process; This is the form I was objecting to in an earlier post, on the grounds that the signal assignments don't match standard synthesis templates. EVERY ONE of the five synthesis tools I tried gave exactly the results you might hope for: "msb" is directly connected to count[7], "q" is directly connected to count[7:0], "tc" is the output of an AND gate looking at all eight bits of count. ~~~~~~~ Form 2: Clocked process, with outputs assigned based on next-state value of counter variable. ~~~~~~~ process(clock, reset) variable count: unsigned(7 downto 0); begin if reset = '1' then count := (others => '0'); q <= std_logic_vector(count); msb <= count(7); if count = (count'range => '1') then tc <= '1'; else tc <= '0'; end if; elsif rising_edge(clock) then count := count + 1; q <= std_logic_vector(count); msb <= count(7); if count = (count'range => '1') then tc <= '1'; else tc <= '0'; end if; end if; end process; You'll note that this is quite a bit nastier because it's necessary to assign to the outputs both in the reset and in the clocked branch, otherwise the "q" and "count" registers will have subtly different behaviour and could not be merged. All five tools gave correct results, but two tools failed to merge the duplicate registers they had created for count and q. Of course, it is entirely possible that those duplicate registers might be merged later, during place-and-route, as they were indeed exact duplicates. I'm not quite sure what to think now. Form 1 still does not really appeal. In particular, it cannot be reproduced in Verilog. Form 2 gives registered outputs for everything - not even the very simplest combinational logic between flops and outputs - and maps well to Verilog, but it's disappointing that some tools didn't merge the duplicate registers and there is no doubt that it's clumsier to code, especially if there's an asynchronous reset in the process. One final data point: The style of asynch reset that has been suggested here on several occasions, allowing you to reset some but not all of a process's registers without implying unwanted enable logic, worked as expected in all five tools I tried: process (clock, reset) variable count: unsigned(7 downto 0); begin if rising_edge(clock) then count_pipe <= count; -- count_pipe isn't reset count := count + 1; end if; if reset = '1' then count := (others => '0'); end if; end process; This form also maps happily to Verilog. Comments welcomed. -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated. |
|
#2
| |||
| |||
| With apologies for replying to myself... On Mon, 18 Aug 2008 16:53:12 +0100, Jonathan Bromley wrote: > process (clock, reset) > variable count: unsigned(7 downto 0); > begin > if rising_edge(clock) then > count_pipe <= count; -- count_pipe isn't reset > count := count + 1; > end if; > if reset = '1' then > count := (others => '0'); > end if; > end process; > >This form also maps happily to Verilog. Erm, no it doesn't. Since Verilog has no rising_edge test, you can't sensibly do this in Verilog. Whoops. -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated. |
|
#3
| |||
| |||
| On Aug 18, 11:53 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com> wrote: > I have been able to try this on five different > synthesis tools, spanning the whole range of > cost and FPGA-vs-ASIC. The results surprised > me a little - it's a long time since I did such > a complete survey. .... > Comments welcomed. > -- Jonathan, This is interesting, but I'm not sure exactly what conclusions to draw. At least, no incorrect logic was generated (sighs of relief from vendors involved). This smells like it could turn into a hunt for cases which *do* mess up synthesizers, but that's a lot of experimenting. This is also interesting in that you've performed experiments, guided by some hypotheses, and examined the results in light of those hypotheses. Smells a bit like the scientific method to me. Clearly, you don't get this usenet thing at all :-) - Kenn |
|
#4
| |||
| |||
| On Aug 18, 11:53 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com> wrote: > OK, so I tried the following synthesis example - > various declarations omitted to save space. > I have been able to try this on five different > synthesis tools, spanning the whole range of > cost and FPGA-vs-ASIC. The results surprised > me a little - it's a long time since I did such > a complete survey. > > ~~~~~~~ > Form 1: Clocked process, with combinational output logic > outside the usual clocked if..else...endif block. > ~~~~~~~ > > process(clock, reset) > variable count: unsigned(7 downto 0); > begin > -- 8-bit counter, clocked with async reset > if reset = '1' then > count := (others => '0'); > elsif rising_edge(clock) then > count := count + 1; > end if; > -- Combinational logic > q <= std_logic_vector(count); > msb <= count(7); > if count = (count'range => '1') then > tc <= '1'; > else > tc <= '0'; > end if; > end process; > > This is the form I was objecting to in an earlier post, > on the grounds that the signal assignments don't match > standard synthesis templates. EVERY ONE of the five > synthesis tools I tried gave exactly the results you > might hope for: "msb" is directly connected to count[7], > "q" is directly connected to count[7:0], "tc" is the > output of an AND gate looking at all eight bits of count. > > ~~~~~~~ > Form 2: Clocked process, with outputs assigned based on > next-state value of counter variable. > ~~~~~~~ > > process(clock, reset) > variable count: unsigned(7 downto 0); > begin > if reset = '1' then > count := (others => '0'); > q <= std_logic_vector(count); > msb <= count(7); > if count = (count'range => '1') then > tc <= '1'; > else > tc <= '0'; > end if; > elsif rising_edge(clock) then > count := count + 1; > q <= std_logic_vector(count); > msb <= count(7); > if count = (count'range => '1') then > tc <= '1'; > else > tc <= '0'; > end if; > end if; > end process; > > You'll note that this is quite a bit nastier because > it's necessary to assign to the outputs both in the > reset and in the clocked branch, otherwise the > "q" and "count" registers will have subtly different > behaviour and could not be merged. I can't say I follow you on this. A reset input by definition defines the state of all registers, state and output. Why would you want to assign the outputs to be dependant on the previous state when the reset is asserted??? I have never done this since it was not the desired behavior. Oh, I guess it is because you are trying to force the use of the carry chain. Do you have any reason to believe that this is needed? Considering that the if (count = 1's) in the reset code is redundant (at this point count is always the value 0), this just seems so verbose. > All five tools gave correct results, but two tools > failed to merge the duplicate registers they had > created for count and q. Of course, it is entirely > possible that those duplicate registers might be > merged later, during place-and-route, as they were > indeed exact duplicates. > > I'm not quite sure what to think now. Form 1 still > does not really appeal. In particular, it cannot be > reproduced in Verilog. Form 2 gives registered outputs > for everything - not even the very simplest combinational > logic between flops and outputs - and maps well to Verilog, > but it's disappointing that some tools didn't merge the > duplicate registers and there is no doubt that it's > clumsier to code, especially if there's an asynchronous > reset in the process. What about form B, not using a variable since it adds nothing to the situation and is clearly making things more difficult. > One final data point: The style of asynch reset > that has been suggested here on several occasions, > allowing you to reset some but not all of a process's > registers without implying unwanted enable logic, > worked as expected in all five tools I tried: > > process (clock, reset) > variable count: unsigned(7 downto 0); > begin > if rising_edge(clock) then > count_pipe <= count; -- count_pipe isn't reset > count := count + 1; > end if; > if reset = '1' then > count := (others => '0'); > end if; > end process; I personally don't care for this since it is 1) complex and 2) not the same as your other code that sets the values of the outputs. Rick |
|
#5
| |||
| |||
| On Mon, 18 Aug 2008 10:46:14 -0700 (PDT), kennheinrich@sympatico.ca wrote: >This is interesting, but I'm not sure exactly what conclusions to >draw. Me neither. I should have presented the context a little better: "Form 1" was, for all practical purposes, my preferred way to write a process with internal synchronous state that has outputs that are a function of that state, guaranteeing that all outputs come direct from a register with no intervening logic. There was never any doubt that tools would generate correct logic from it, but the description inherently creates duplicate registers and I wanted to get a bead on whether tools would reliably merge those duplicated registers; my (poorly documented) experience in the past has been that it's usually OK. The answer: some do, some don't. "Form 2" is something I've tried before and rejected because it doesn't follow the usual "industry standard" synthesis coding guidelines, and is too easily abused for my taste. However, it's come up in discussion here a few times recently, and I wanted to take a second look at whether it works. It is potentially a clean and convenient way of describing the Moore-machine behaviour, but putting some combinational logic between the internal state and the ultimate outputs of the process. To my surprise, all tools did The Right Thing (TM) with it. "Form 3" was just a variant of Form 2 that I played with while I had an example in the cooking-pot; the difference is in the manner of describing asynchronous reset. It has the useful property, not available with the conventional clocked process template, that in a single process you can describe some registers that have asynch reset and some that don't. Again, tools are OK with it, which I wasn't necessarily expecting. Neither Form 2 nor Form 3 can be made to work in Verilog, which is not good news for those of us who are bilingual. > This smells like it could turn into a hunt for >cases which *do* mess up synthesizers, but that's a lot of >experimenting. Yeah. Far too much for a non-paying project :-) >This is also interesting in that you've performed experiments, guided >by some hypotheses, and examined the results in light of those >hypotheses. Smells a bit like the scientific method to me. Clearly, >you don't get this usenet thing at all :-) Oh, don't worry; I can do unjustified inflammatory assertion when the need arises :-) Thanks -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated. |
|
#6
| |||
| |||
| On Mon, 18 Aug 2008 11:39:42 -0700 (PDT), rickman wrote: >> it's necessary to assign to the outputs both in the >> reset and in the clocked branch, otherwise the >> "q" and "count" registers will have subtly different >> behaviour and could not be merged. > >I can't say I follow you on this. A reset input by definition defines >the state of all registers, state and output. Not if I write a description in which some of the registers are reset and some aren't, surely? > Why would you want to >assign the outputs to be dependant on the previous state when the >reset is asserted??? I have never done this since it was not the >desired behavior. Oh, I guess it is because you are trying to force >the use of the carry chain. No, nothing as smart as that. It's just a simple thing about the usual synthesisable clocked process: process(clk) begin if reset = '1' then Q0 <= '0'; -- reset, but never clocked Q1 <= '0'; -- reset and clocked, OK elsif rising_edge(clk) then Q1 <= D1; -- reset and clocked, OK Q2 <= D2; -- clocked but never reset end if; end process; The usage of Q0 and Q2 is unsatisfactory because... - Q0 is a latch, enabled by reset, with constant input - Q2 is a regular flop with (reset = '0') as its clock enable So, what happens when I wish to describe some kind of pipeline in which the first stage has an asynch reset but the later stages do not? That's a sensible design; if you know that the clock will tick several times during reset, then you don't need to reset anything but the first stage of the pipeline because all later stages will flush through by clocked action during the reset interval. But how to describe that? You need TWO PROCESSES, one for the register that HAS a reset and one for the registers that LACK a reset. Of course, synch reset doesn't suffer this problem - you can freely apply it to individual registers, and not to others, in a single process. All of that was the motivation for my final example, which you didn't like... >> begin >> if rising_edge(clock) then >> count_pipe <= count; -- count_pipe isn't reset >> count := count + 1; >> end if; >> if reset = '1' then >> count := (others => '0'); >> end if; >> end process; > I personally don't care for this since it is 1) complex and 2) not the > same as your other code that sets the values of the outputs. I abbreviated the example; it could easily set outputs just as the "Form 2" variant does. But I take the point that it is unfamiliar (surely not really "complex"?) and, as someone else has pointed out, it's not too nice to have a piece of code that says Do-Lots-Of-Complicated-Stuff only to have the rug pulled out from under you by an If-The-World-Is-About-To-End condition right at the end of the process. It's better to know about those global things right up front. -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated. |
|
#7
| |||
| |||
| On Aug 18, 4:38 pm, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com> wrote: > On Mon, 18 Aug 2008 11:39:42 -0700 (PDT), rickman wrote: > >> it's necessary to assign to the outputs both in the > >> reset and in the clocked branch, otherwise the > >> "q" and "count" registers will have subtly different > >> behaviour and could not be merged. > > >I can't say I follow you on this. A reset input by definition defines > >the state of all registers, state and output. > > Not if I write a description in which some of the registers > are reset and some aren't, surely? Of course you can define any world you wish to work in. I was referring to the world of FPGA design. There a global async reset is nearly always provided and needs to be specified. The standard template is mapped to the global reset quite well by the tools. In that context, there is no reason to leave any register uncontrolled on reset (unless you have some very odd requirements) and failure to do so can result in unpredictable power up behavior. I don't have to consider the entire universe of possibilities. I just have to consider the universe that I choose to work in and I don't want to make my life difficult by not controlling the power up state of registers in my design. It also helps with simulation a great deal! > > Why would you want to > >assign the outputs to be dependant on the previous state when the > >reset is asserted??? I have never done this since it was not the > >desired behavior. Oh, I guess it is because you are trying to force > >the use of the carry chain. > > No, nothing as smart as that. It's just a simple thing > about the usual synthesisable clocked process: > > process(clk) > begin > if reset = '1' then > Q0 <= '0'; -- reset, but never clocked > Q1 <= '0'; -- reset and clocked, OK > elsif rising_edge(clk) then > Q1 <= D1; -- reset and clocked, OK > Q2 <= D2; -- clocked but never reset > end if; > end process; > > The usage of Q0 and Q2 is unsatisfactory because... > - Q0 is a latch, enabled by reset, with constant input > - Q2 is a regular flop with (reset = '0') as its clock enable > > So, what happens when I wish to describe some kind of pipeline > in which the first stage has an asynch reset but the later > stages do not? That's a sensible design; if you know that > the clock will tick several times during reset, then you > don't need to reset anything but the first stage of the > pipeline because all later stages will flush through > by clocked action during the reset interval. But how > to describe that? You need TWO PROCESSES, one for the > register that HAS a reset and one for the registers > that LACK a reset. Of course, synch reset doesn't suffer > this problem - you can freely apply it to individual > registers, and not to others, in a single process. Again, you don't explain the context of your async reset. If it is the global reset I see no reason to leave it off of any registers in your design. A sync reset is one that is typically used at any time during operation. The async reset is typically mapped to the global reset. If it does not, IMHO, the async reset does not belong in a synchronous design. I avoid the problem by avoiding it! > All of that was the motivation for my final example, > which you didn't like... > > >> begin > >> if rising_edge(clock) then > >> count_pipe <= count; -- count_pipe isn't reset > >> count := count + 1; > >> end if; > >> if reset = '1' then > >> count := (others => '0'); > >> end if; > >> end process; > > I personally don't care for this since it is 1) complex and 2) not the > > same as your other code that sets the values of the outputs. > > I abbreviated the example; it could easily set outputs just as > the "Form 2" variant does. But I take the point that it is > unfamiliar (surely not really "complex"?) and, as someone else > has pointed out, it's not too nice to have a piece of code that > says Do-Lots-Of-Complicated-Stuff only to have the rug pulled out > from under you by an If-The-World-Is-About-To-End condition > right at the end of the process. It's better to know about > those global things right up front. I will point out that the above example can fail to initialize count_pipe. The above should produce two registers and only the first, count, will be reset. Why would you want to do that??? So I still fail to see your motivation, or at least I don't share it. Rick |
|
#8
| |||
| |||
| rickman wrote: > I can't say I follow you on this. A reset input by definition defines > the state of all registers, state and output. Why would you want to > assign the outputs to be dependant on the previous state when the > reset is asserted??? Maybe I want to describe a block ram and a lut shifter in the same process as some registers. The registers need a reset, but the ram and shifter can't have one. -- Mike Treseler |
|
#9
| |||
| |||
| Jonathan Bromley wrote: > OK, so I tried the following synthesis example - > various declarations omitted to save space. Thanks for all the unbillable hours. > All five tools gave correct results, but two tools > failed to merge the duplicate registers they had > created for count and q. Of course, it is entirely > possible that those duplicate registers might be > merged later, during place-and-route, as they were > indeed exact duplicates. I have yet to see a duplicate register make it all the way through synthesis, but they do sometimes clutter the RTL schematic. The "odd" template seems to tip the algorithm toward doing the merge on the front end. -- Mike Treseler |
|
#10
| |||
| |||
| rickman, first off, let me say that I broadly agree with what you say about FPGAs. But... >I will point out that the above example can fail to initialize >count_pipe. The above should produce two registers and only the >first, count, will be reset. I was careful to qualify the suggestion by noting that there must be enough clocks during reset for the pipe to flush. Given the way reset is likely to be managed on an ASIC design, that is not unreasonable. >Why would you want to do that??? In ASIC technologies, reset is not free. In the example I gave, I need only one active clock during the reset interval to flush the second register with the async-reset contents of the first. That's an entirely plausible scenario. If the downstream processing pipe is long or wide, the area and routing resources saved by *not* resetting it can be worth having. > >So I still fail to see your motivation, or at >least I don't share it. There are lots of ASIC designers out there.... most of the time I'm not one of them, so I absolutely see where you're coming from. But it's not the only point of view. -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated. |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.