Jim Lewis said:
KJ,
True - except in statemachines where you do have the freedom
to do something in a clean organized fashion or otherwise.
Not sure I follow your point. State machines are no different from any
other lines of code where you have the same "freedom
to do something in a clean organized fashion or otherwise" as long as you
implement the required function (which is what I meant by "dictacted by
whatever function it is you are trying to implement") and meet all
performance/area/whatever constraints.
In any case, I'll keep by statement that it is 'usually' the case that the
default in a state machine is to hold the current state not some hard coded
default value and that other assignments that happen to occur within the
state machie logic can 'usually' be factored out and work with the current
state which tends to have the side benefit of improving the
readability/maintainability of the code.
'Usually' means just that, does not mean 'always'.
By putting items in separate logic cones, they cannot be minimized
together.
Sure they can and they do. The 'clock enable' logic can be folded into the
'D' logic or left stripped out. By having the choice of either one or two
separate logic paths to minimize one should have some theoretical advantage.
Typically in an FPGA though, since the basic logic block is a 4-6 input LUT
many times there is no actual advantage if the final LUT stage happens to
have an unused input. The best way to synthesize it though is left to the
synthesizer though...shouldn't affect the code.
I agree, when you default an output to a value, you are locking into a
"no clock enable" style. This is my preference.
That's fine, and unless there is some design requirerement that's what it
is...a preference.
When you don't default an output then you have the freedom to
either assign a constant value (and put logic on D),
not assign a value (hold a value and put logic on CE),
or a mixture of the two. To clarify this, the following
simple examples illustrate this for state.
Consistently putting logic on D (state only, but applies
to outputs also):
<snip code samples>
I confess I only lightly persued the three code samples, I'm assuming that
they purport to implementing the exact same function just varying how you
write the code. Given that, here are some comments on your code.
1. What you'll find if you run this through probably any synthesis tool, is
that the final fitted output is exactly the same even though the source code
is different. Your 'All_Logic_On_D' process may very well use clock enables
and that your 'Logic_On_D_And_CE' might not use any clock enables. Whether
they do or don't is a function of how the synthesis tool chose to implement
it based on what it came up with for the final fitted equations. In any
case, you'll get the same final set of equations regardless of the input
(again, under the assumption that the three different styles really do
implement logically the same stuff).
2. I count 16 lines of code in the 'All_Logic_On_D' process (starting with
the 'if nReset = '0' then' line, 12 lines of code in the 'Logic_On_D_And_CE'
process. Even with your simple example it shows that it costs you 33% extra
in lines of code to code things in the manner of 'All_Logic_On_D' to
implement the exact same function (see point #1). Now if you get paid by
the lines of code that may be a good thing but in general every line of code
has some chance of being wrong so by having 33% extra code you have 33%
higher chance of having some lingering bug.
3. On the readability/maintainability side, both forms are roughly equal
but that is also due to the small size of the example itself. On a more
complicated design the "readability/maintainability" of the
'All_Logic_On_D' form would deteriorate sooner due to the extra, unneeded
33% extra lines of code.
4. Never use an async reset in a state machine. If the trailing edge of the
reset input is not synchronized to the clock you can end up in an
'undefined' state. If the trailing edge is synchronized to the clock then
there is no reason to not use a synchronous coding style. People like to
try to beat me up over never using async resets but I still have yet to run
across the case where it is has really been needed. In any case, even the
ones who like async resets tend to agree that they should never be used in a
state machine. This point is off topic but still worth noting.
I agree with your statement that your coding indirectly 'choose'
the implementation. It would be interesting to see if a synthesis
tool can move logic from the CE to the D logic cone to minimize
the implementation. Anyone have evidence of this?
Yes, I've seen it it makes no difference. Take your example and try it out
and you'll see it too.
My conclusion is that while a favorable mixture of the two is
likely optimal, a random mixture of the two is more
likely worst case.
Nope, they will be equivalent.
Hence, my recommendation, don't randomly
mix the two and hence avoid coding as shown in the process
labeled Mixed_Style.
Agreed, but only due to source code maintainability concerns, not function
or performance.
On the other hand, on many designs, the clock is slow enough
and the part has enough area, so who cares - if it functions
correctly the job is done
. Your boss never asks, "did you
get the fastest/smallest possible design?" They only ask,
"is it done yet?"
And you may get done sooner if you're not writing more code than is
necessary.
My biggest concern is readability, reviewability, and maintainability.
This is another reason I push consistency. Readability (...) improve
when everyone on a project consistently codes in a similar fashion.
But that 'consistent' style should also be fair game for review to
understand the costs (i.e. the extra 33% lines of code and 33% possible
extra latent bugs).
KJ