combinational loops

A

alb

Hi Rick,

On 03/10/2013 05:24, rickman wrote:
[]
That *is* the problem. The second procedure sees the next state rather
than the current state.

That's the reason why the order of procedures matter. I let the higher
FSM (the one that supposedly 'controls' everything) be the last to start
and then respectively the second in rank and so on...
I thought they were all registers? If not, they aren't state variables.

They *are* registered. What I meant is that if you write this:

<code>
a := a + 1;
</code>

then 'a' is used before it is assigned, leading to a register. This is
what happens in my fsm procedure, whether the procedure has a single
case-switch which rolls over the state value, using it before assigning it.

[]
And therein lies the problem. When using a single variable like this,
if some state variable have been updated but not others, the FSM gets
very complex.

I don't get this. My state variable at each state depends on several
conditions, some of them been states of another FSM (like you would have
with a counter), where is the problem?
The isolated procedures for updating each state variable
in your FSM have to be aware of one another and the order in which they
are invoked. This greatly complicates the code and understanding of it.
I would find that to be impossibly difficult to use. I don't consider
this to be useful decomposition.

See the following snippet of code:

<code>
-------------------------------------------------------------------------------
procedure writ_read (
state_v : inout state_t;
mstate_v : in mstate_t;
nstate_v : in nstate_t) is
begin
case state_v is
when IDLE =>
if mstate_v = START_READ or nstate_v = START_READ then
state_v := READ_BGN;
elsif mstate_v = START_WRITE or nstate_v = START_WRITE then
state_v := WRITE_BGN;
end if;
when READ_BGN =>
state_v := READ_END; -- this is one clock cycle
nRD_v := not nRD_v;
when READ_END =>
state_v := IDLE;
nRD_v := not nRD_v;
DATA_v := DATA;
when WRITE_BGN =>
state_v := WRITE_END; -- this is one clock cycle
nWR_v := not nWR_v;
when WRITE_END =>
state_v := DONE;
nWR_v := not nWR_v;
when DONE =>
state_v := IDLE;
DATA_v := (others => 'Z'); -- release the bus
when others => null;
end case;
end procedure writ_read;
</code>

the 'awareness' you refer to is in the IDLE state case, where the 'if'
branch reacts on the others' state variables... Being the author of this
code I certainly cannot see the 'complication' that lies behind it, but
please advise on how to write it *more* clear than this [1].

[]
Yes, Mealy and Moore are not often used in a strict sense, but the point
is access to the *next* value of the state rather than the current
value. This lets you get registered outputs out on *this* clock edge
rather than having them wait a clock cycle.

'this' or 'that' clock cycle does not really matter to me, latency apart
I get the same throughput.
 
A

Andy

This is a weak argument. If a signal that is a counter can be 'seen'
and used for some other than the original intended purpose, then so
can a variable...you simply put the 'other' code inside that same
process and watch things not work in the same way as when the counter
is a signal. Pretending you have some sort of firewall here doesn't
make it one.

If you really believed this, why bother with more than one entity/architecture containing a single process in the entire design? That way you can easily find all your signals and see how they are used, all in one file!

Assuming that not all of the code is in one process per architecture, but that the processes are limited in size and in purpose, then understanding where and how a variable is used is much simpler than for a signal under the same circumstances.

If someone later wants to use a variable for some other purpose, then they have to add code to its process. This is much more likely to be noticed, and if not appropriate, flagged in review (speaking of design process issues....)

There is no firewall to prevent people from doing stupind things, only fromdoing them in ways that are difficult to catch in review.

You do raise a good point about capturing waveforms of variables. It soundslike a tool issue to be solved. In the meantime, I might suggest local signals declared in a block statement surrounding each process.

There have also been suggestions in the past to amend the standard to allowsignals to be declared locally in a process (and therefore not visible outside the process). That way, if you want the suspended update semantics, you can have them without having to give up on encapsulation (or jump throughmore hoops to keep it).

Good code design standards (one of which is encapsulation) are intended to avoid many problems before compilation, rather than waiting for a testbenchto be written to expose them in simulation, or even worse, system integration.

Andy
 
A

alb

I forgot to add a note to my previous post.

the 'awareness' you refer to is in the IDLE state case, where the 'if'
branch reacts on the others' state variables... Being the author of this
code I certainly cannot see the 'complication' that lies behind it, but
please advise on how to write it *more* clear than this [1].

[1] I'm currently trying to work on a 'message passing' method which can
provide a cleaner interface and increase the level of encapsulation,
similar to what Andy referred to as 'explicit control (start) and status
(finished) parameters'.

I've followed a similar path in a C application for an embedded system
and the pay off was huge.
 
K

KJ

If you really believed this, why bother with more than one entity/architecture containing
a single process in the entire design? That way you can easily find all your signals and
see how they are used, all in one file!

You're missing your original point which I was responding to with this comment.
Assuming that not all of the code is in one process per architecture, butthat the
processes are limited in size and in purpose, then understanding where and how a
variable is used is much simpler than for a signal under the same circumstances.

That's an assumption and, unless the code is very fresh in your mind a poorone to make. Your original point was that making something a variable would somehow isolate an implementation change from rippling into some unintended operation. But if you change the implementation of signal or variable 'xyz', you need to search for every usage of 'xyz' in the entity (and beyond if 'xyz' is an entity output or affects an entity output) and insure you won't break something. Thinking that just because 'xyz' is a variable willin any limit the scope of that search is incorrect. You'll still have to do a text search on 'xyz'. If you're not doing that, you're simply hoping that the implementation change has no other unintended effects.
If someone later wants to use a variable for some other purpose, then they have to add
code to its process. This is much more likely to be noticed, and if not appropriate,
flagged in review (speaking of design process issues...)

I doubt it...but accept that you may have seen inappropriate usage of variables being flagged in a review where similarly inappropriate usage of a signal was not caught in a similar review.
There is no firewall to prevent people from doing stupind things, only from doing
them in ways that are difficult to catch in review.

Not sure what you think is a 'stupid' thing. You've already conceded that there may be appropriate usages that violate your statement.

Your suggestion was that it is somehow easier to search for 'xyz' in the process rather than the architecture. My point is that you have to do the search for 'xyz' and that you should use a tool. If the tool you're using issimply your eyeball scan of the code (or the eyeballs of a review team) then you're right, but if you're using your eyeball (and the eyeball of others) to scan you're using the wrong tool. You should be using the search function of your text editor. When you use that tool you'll get to the "xyz not found" with exactly the same effort regardless of whether 'xyz' is a signal or variable and regardless of the size of the architecture being searched.
You do raise a good point about capturing waveforms of variables. It sounds like a tool
issue to be solved.

It is a gripe of mine too, but it doesn't seem to be a tool issue that willgo away soon.
In the meantime, I might suggest local signals declared in a block
statement surrounding each process.

Yep.


There have also been suggestions in the past to amend the standard to allow signals
to be declared locally in a process (and therefore not visible outside the process).
That way, if you want the suspended update semantics, you can have them without having
to give up on encapsulation (or jump through more hoops to keep it).

And a good suggestion at that.
Good code design standards (one of which is encapsulation) are intended to avoid many
problems before compilation, rather than waiting for a testbench to be written to expose > them in simulation, or even worse, system integration.

I agree completely here, but this is off on another tangent. We simply seem to disagree on whether the effort to check whether a change will have an unintended effect is any different when using the most appropriate tool forthe job.

Kevin Jennings
 
A

alb

Hi Kevin,

On 04/10/2013 03:10, KJ wrote:
[]
Your original point was that making something a
variable would somehow isolate an implementation change from rippling
into some unintended operation. But if you change the implementation
of signal or variable 'xyz', you need to search for every usage of
'xyz' in the entity (and beyond if 'xyz' is an entity output or
affects an entity output) and insure you won't break something.
Thinking that just because 'xyz' is a variable will in any limit the
scope of that search is incorrect. You'll still have to do a text
search on 'xyz'. If you're not doing that, you're simply hoping that
the implementation change has no other unintended effects.

while if you have a signal 'xyz' and change its behavior you *must*
verify the impact in the rest of the architecture and if needed, as you
said, beyond the entity boundary, with a variable your search is limited
to the process where it has been declared.

Moreover, if your variable logic change does not affect the signals
logic that are related to it within that process, you do not have to
search beyond the process itself. Meaning you have kept the interface
between processes the same, while changing the internal logic of the
process, hence providing encapsulation.

[]
Your suggestion was that it is somehow easier to search for 'xyz' in
the process rather than the architecture. My point is that you have
to do the search for 'xyz' and that you should use a tool. If the
tool you're using is simply your eyeball scan of the code (or the
eyeballs of a review team) then you're right, but if you're using
your eyeball (and the eyeball of others) to scan you're using the
wrong tool. You should be using the search function of your text
editor. When you use that tool you'll get to the "xyz not found"
with exactly the same effort regardless of whether 'xyz' is a signal
or variable and regardless of the size of the architecture being
searched.

Having the variable local scope nobody prevents me calling all variables
with the same name; I may have tens of variables all named 'cnt' but
having a completely different logic for each individual process they
belong too. Your tool now is in your way instead.

When interfaces between processes (signals) have been defined you only
need to make sure the change to the logic does not affect the interface
and I'm not sure there's a tool out there (other than a simulator) to
help you out.
 
R

rickman

Hi Rick,

On 03/10/2013 05:24, rickman wrote:
[]
That *is* the problem. The second procedure sees the next state rather
than the current state.

That's the reason why the order of procedures matter. I let the higher
FSM (the one that supposedly 'controls' everything) be the last to start
and then respectively the second in rank and so on...

This is the awkward part. The way you have it written, procedures get
the "next" state of variables that have been updated already and the
"current" state of variables still to be updated! The current and next
states of a registered variable correspond to the outputs and inputs of
the register respectively.

When using signals, the order of sequential statements is not important,
but for variables it *is*. By partitioning the variable assignments
this way you make it difficult for the designer to keep track of whether
variables are in the current state or next state mode.

Normally the various FSMs of a design all work on the same clock edge so
the code needs to reflect that. If a signal is used it is not actually
updated until after a delta cycle and so all procedures have the same
input values regardless of the order called.

I don't get this. My state variable at each state depends on several
conditions, some of them been states of another FSM (like you would have
with a counter), where is the problem?

The problem is that in hardware each register has inputs and outputs.
When you use a variable before it is assigned you are using the output
of the register, when you use the variable after it has been assigned
you are using the output of the logic and the input to the register.

Try drawing some logic blocks (no need to actually define the gates)
that implement your design. I bet either a) the resulting logic is not
what you are picturing in your mind or b) the resulting logic is just
not correct.

The isolated procedures for updating each state variable
in your FSM have to be aware of one another and the order in which they
are invoked. This greatly complicates the code and understanding of it.
I would find that to be impossibly difficult to use. I don't consider
this to be useful decomposition.

See the following snippet of code:

<code>
-------------------------------------------------------------------------------
procedure writ_read (
state_v : inout state_t;
mstate_v : in mstate_t;
nstate_v : in nstate_t) is
begin
case state_v is
when IDLE =>
if mstate_v = START_READ or nstate_v = START_READ then
state_v := READ_BGN;
elsif mstate_v = START_WRITE or nstate_v = START_WRITE then
state_v := WRITE_BGN;
end if;
when READ_BGN =>
state_v := READ_END; -- this is one clock cycle
nRD_v := not nRD_v;
when READ_END =>
state_v := IDLE;
nRD_v := not nRD_v;
DATA_v := DATA;
when WRITE_BGN =>
state_v := WRITE_END; -- this is one clock cycle
nWR_v := not nWR_v;
when WRITE_END =>
state_v := DONE;
nWR_v := not nWR_v;
when DONE =>
state_v := IDLE;
DATA_v := (others => 'Z'); -- release the bus
when others => null;
end case;
end procedure writ_read;
</code>

the 'awareness' you refer to is in the IDLE state case, where the 'if'
branch reacts on the others' state variables... Being the author of this
code I certainly cannot see the 'complication' that lies behind it, but
please advise on how to write it *more* clear than this [1].

Has mstate_v or nstate_v been updated in their procedures yet? You have
to know this in order to know what value they will have.

This is exactly the type of problems that happen when designers forget
they are describing hardware rather than writing software.

'this' or 'that' clock cycle does not really matter to me, latency apart
I get the same throughput.

Ok, so now I understand. You don't *care* about what hardware is
produced. Your design may be implemented very inefficiently, but it
doesn't matter. I'm not sure if you care about latency or not. In most
of my designs latency *is* an issue so I use HDL to describe the
hardware rather than writing software and letting the chips fall where
they may. (pun intended)

Clock cycles count very much in my designs as well.

Do you care about the clock speed? By using the next state value of a
variable the logic created will most likely be slower than using the
current state value since it is daisy chained. If you have three FSMs
as in your earlier example machine C will be a function of all the
inputs to FSM B as which is a function of all the inputs to FSM A and
very likely result in cascaded or duplicated logic running three times
slower than a design all based on the current state of a variable or
signal.
 
R

rickman

You do raise a good point about capturing waveforms of variables. It sounds like a tool issue to be solved. In the meantime, I might suggest local signals declared in a block statement surrounding each process.

Variables are handled differently in simulation because they *are*
different. A signal is never updated until the end of a delta cycle.
Variables can be updated at any time. How do you plot a variable having
three values in the same delta cycle? The ability to show signals after
a simulation has started is only available if the flag to save *all*
simulation data is set. This takes up a lot of disk space and makes the
simulation run more slowly. No free lunches... To do this for
variables would require saving a lot of additional information.
 
A

alb

Hi Rick,

On 04/10/2013 15:19, rickman wrote:
[]
That's the reason why the order of procedures matter. I let the higher
FSM (the one that supposedly 'controls' everything) be the last to start
and then respectively the second in rank and so on...
[]
When using signals, the order of sequential statements is not important,
but for variables it *is*. By partitioning the variable assignments
this way you make it difficult for the designer to keep track of whether
variables are in the current state or next state mode.

Read from top to bottom, this may help. The synthesis tool seem to get
it pretty straight forward.
Normally the various FSMs of a design all work on the same clock edge so
the code needs to reflect that. If a signal is used it is not actually
updated until after a delta cycle and so all procedures have the same
input values regardless of the order called.

if your state depends on a value why do you bother so much if this value
happens in a specific clock cycle? On top of this, I'm not thinking in
terms of clock cycles, my FSM remains in a state until the other one has
completed whatever it needs to complete. Timing has completely
disappeared in my logic, what matters is only the functionality.

[]
I don't get this. My state variable at each state depends on several
conditions, some of them been states of another FSM (like you would have
with a counter), where is the problem?
[]
When you use a variable before it is assigned you are using the output
of the register, when you use the variable after it has been assigned
you are using the output of the logic and the input to the register.

a variable can infer both a register and a wire as I already posted:
<code>
process (clk)
variable something : std_logic;
if rising_edge(clk) then
if reset = '1' then
something := '0';
else
output_b <= something or input c; -- using the previous clock's
value of 'something' infers a register
something := input_a and input_b; -- comb. logic for a new value
output_a <= something or input_c; -- which is used immediately,
not registered here
end if;
end if;
end process;
</code>

while a signal in a clocked process can only generate registers. That's
a flexibility I like to profit from.
Try drawing some logic blocks (no need to actually define the gates)
that implement your design. I bet either a) the resulting logic is not
what you are picturing in your mind or b) the resulting logic is just
not correct.

They are three FSM with two counters and few registers, whether this is
correct or not I'm not sure, that is why I simulate it. Being correct or
wrong has nothing to do with the style used.
See the following snippet of code:

<code>
-------------------------------------------------------------------------------

procedure writ_read (
state_v : inout state_t;
mstate_v : in mstate_t;
nstate_v : in nstate_t) is
begin
case state_v is
when IDLE =>
if mstate_v = START_READ or nstate_v = START_READ then
state_v := READ_BGN;
elsif mstate_v = START_WRITE or nstate_v = START_WRITE then
state_v := WRITE_BGN;
end if;
when READ_BGN =>
state_v := READ_END; -- this is one clock cycle
nRD_v := not nRD_v;
when READ_END =>
state_v := IDLE;
nRD_v := not nRD_v;
DATA_v := DATA;
when WRITE_BGN =>
state_v := WRITE_END; -- this is one clock cycle
nWR_v := not nWR_v;
when WRITE_END =>
state_v := DONE;
nWR_v := not nWR_v;
when DONE =>
state_v := IDLE;
DATA_v := (others => 'Z'); -- release the bus
when others => null;
end case;
end procedure writ_read;
</code>
[]
Has mstate_v or nstate_v been updated in their procedures yet? You have
to know this in order to know what value they will have.

Why should I care? When the clock will tick the state_v register will
either move on or stay where it is according to the values of mstate_v
or nstate_v for *that* clock cycle. I'm not thinking on *when* the state
changes, I actually do not want to rely on timing since I may need to
add a pipeline stage to get an operation done, while still keep the
functionality in place.
This is exactly the type of problems that happen when designers forget
they are describing hardware rather than writing software.

You are certainly entitled to draw any conclusion and I do not intend to
change your opinion, I can only say that I see the flops and gates as
you claim you're capable to do with your style.

[]
Ok, so now I understand. You don't *care* about what hardware is
produced.

This is what you say, not me.
Your design may be implemented very inefficiently, but it
doesn't matter.

In my case, area is not an issue and timing...well I can argue that if I
half the clock rate I still get what I need (I'm only too late in the
project phase to debate about the system clock rate!).

Having said that, my code needs to be ported and extended on different
FPGAs and my pure goal is readability. Writing the building blocks
(procedures) to allow a more complex functionality to be added later is
more important than your acclaimed inefficiency.
I'm not sure if you care about latency or not.

why are you not sure? What is your point in doubting on this?
In most
of my designs latency *is* an issue so I use HDL to describe the
hardware rather than writing software and letting the chips fall where
they may. (pun intended)

When latency *is* a problem than you're overall speed starts to suffer
since you cannot pipeline your design.
Clock cycles count very much in my designs as well.

While counting how many clock cycles there are between two operations
make sense (latency), I do not see what sense makes doing the operation
at the 4302423th clock cycle vs 4302424th, but again it all depends on
the specs.
Do you care about the clock speed? By using the next state value of a
variable the logic created will most likely be slower than using the
current state value since it is daisy chained.

Why you keep saying I'm using the 'next state'? A synchronous flop
sensitive to a clock edge can *only* be sensitive to values from the
past. If you manage to get it to be sensitive to values from the future
I'll be interested to see it.

It's a one process only, every register only reacts on a clock edge, the
value of a state depends only on the value of a combination of registers
which have been updated in the previous clock, certainly not in the next
clock cycle.
If you have three FSMs
as in your earlier example machine C will be a function of all the
inputs to FSM B as which is a function of all the inputs to FSM A and
very likely result in cascaded or duplicated logic running three times
slower than a design all based on the current state of a variable or
signal.

You are entitled to /believe/ that, I normally verify what I say with a
test and if it proves me wrong or right than there's nothing else I need
to believe.
 
K

KJ

On Friday, October 4, 2013 4:55:43 AM UTC-4, alb wrote:
while if you have a signal 'xyz' and change its behavior you *must*
verify the impact in the rest of the architecture and if needed, as you
said, beyond the entity boundary, with a variable your search is limited
to the process where it has been declared.

Your search does not end at the end of a process (or entity) just because you use a variable. Consider the following simple statement added within a process where 'xyz' is the variable:
some_sig <= xyz;
By your reasoning, you would not need to verify the impact of 'some_sig' since 'xyz' is a local variable and cannot escape. That reasoning is incorrect. My only point is that the use of a *variable* does not aid you in any way when it comes to making a change to the implementation of that variable(i.e. changing the logic that generates the variable). I'm not debating whether using the variable localizes the use or whether or not using variables is 'good' or not.
Moreover, if your variable logic change does not affect the signals
logic that are related to it within that process, you do not have to
search beyond the process itself. Meaning you have kept the interface
between processes the same, while changing the internal logic of the
process, hence providing encapsulation.

Encapulation is not the point. This sub-thread was about how supposedly using a variable rather than a signal somehow provides additional protection from some unintended functional changes when the design is modified in the future. Already mentioned was that locally scoped signals within a block statement would be equivalent in scope with a variable, but the locally scoped signal could still escape the block statement in exactly the same manneras shown for a variable. Therefore, the search for dependencies would continue outside the local scope whether that scope was a process or a block.
Having the variable local scope nobody prevents me calling all variables
with the same name; I may have tens of variables all named 'cnt' but
having a completely different logic for each individual process they
belong too. Your tool now is in your way instead.

Might I suggest that if you have lots of variables all named the same, thatyou are likely leaving a messy design trail for somebody to have to decipher down the road. You can also reuse a particular variable and give it completely different functional definitions within a process due to the sequential nature of a process...but that doesn't mean you should do things that way.
When interfaces between processes (signals) have been defined you only
need to make sure the change to the logic does not affect the interface
and I'm not sure there's a tool out there (other than a simulator) to
help you out.

The text editor is one effective tool but yes it fails if everything is named the same and you depend on scope alone to sort it out. The dataflow window in a simulator will give you precisely what you need. It will show youall dependencies no matter they are in the entire simulation model (i.e. not limited in scope by process or entity). It works with signals...not variables. Score another for signal and a whiff for variables.

Kevin Jennings
 
A

Andy

When using signals, the order of sequential statements is not
important, but for variables it *is*.

The order of read (access) relative to write (update) is not important, but the order of writes relative to other writes is!

Consider sequential signal assignment statements in a process:

count <= 0;
if a then
count <= count + 1;
end if;
if b then
count <= count; -- ;^)
end if;

This is why I consider sequential signal assignments pseudo-sequential. Some aspects are sequential, others are not.

Variable assignments are purely sequential.

Andy
 
R

rickman

Hi Rick,

On 04/10/2013 15:19, rickman wrote:
[]
That *is* the problem. The second procedure sees the next state rather
than the current state.

That's the reason why the order of procedures matter. I let the higher
FSM (the one that supposedly 'controls' everything) be the last to start
and then respectively the second in rank and so on...
[]
When using signals, the order of sequential statements is not important,
but for variables it *is*. By partitioning the variable assignments
this way you make it difficult for the designer to keep track of whether
variables are in the current state or next state mode.

Read from top to bottom, this may help. The synthesis tool seem to get
it pretty straight forward.
Normally the various FSMs of a design all work on the same clock edge so
the code needs to reflect that. If a signal is used it is not actually
updated until after a delta cycle and so all procedures have the same
input values regardless of the order called.

if your state depends on a value why do you bother so much if this value
happens in a specific clock cycle? On top of this, I'm not thinking in
terms of clock cycles, my FSM remains in a state until the other one has
completed whatever it needs to complete. Timing has completely
disappeared in my logic, what matters is only the functionality.

I *design* hardware. If I don't care when or how something happens I
can use graphical tools and just skip HDL altogether... which I don't do
because I find it much easier to just "do it". Why have multiple
methodologies for designing FSMs when one method works, is simple to
design and simple to read?

I don't get this. My state variable at each state depends on several
conditions, some of them been states of another FSM (like you would have
with a counter), where is the problem?
[]
When you use a variable before it is assigned you are using the output
of the register, when you use the variable after it has been assigned
you are using the output of the logic and the input to the register.

a variable can infer both a register and a wire as I already posted:
<code>
process (clk)
variable something : std_logic;
if rising_edge(clk) then
if reset = '1' then
something := '0';
else
output_b<= something or input c; -- using the previous clock's
value of 'something' infers a register
something := input_a and input_b; -- comb. logic for a new value
output_a<= something or input_c; -- which is used immediately,
not registered here
end if;
end if;
end process;
</code>

while a signal in a clocked process can only generate registers. That's
a flexibility I like to profit from.

You aren't addressing my point. You either don't know what hardware is
being generated from your code or you don't care. You have indicated
you don't try to control the hardware generated, so I guess that is
what's going on, you don't care. I do care. I *always* want to know
what hardware is generated and have control.

They are three FSM with two counters and few registers, whether this is
correct or not I'm not sure, that is why I simulate it. Being correct or
wrong has nothing to do with the style used.

No but the efficiency will vary and is *very much* a function of style.

[]
Has mstate_v or nstate_v been updated in their procedures yet? You have
to know this in order to know what value they will have.

Why should I care? When the clock will tick the state_v register will
either move on or stay where it is according to the values of mstate_v
or nstate_v for *that* clock cycle. I'm not thinking on *when* the state
changes, I actually do not want to rely on timing since I may need to
add a pipeline stage to get an operation done, while still keep the
functionality in place.

You should care because depending on whether the variables have been
updated will determine what FSM you are *actually* designing. Designing
hardware without understanding what hardware is generated is a *bad* idea.


You are certainly entitled to draw any conclusion and I do not intend to
change your opinion, I can only say that I see the flops and gates as
you claim you're capable to do with your style.

But you have said you don't care how the FSMs depend on one another. If
you don't care, how can you know? Much of your code will produce
combinatorial logic without registers in the path. It is entirely
possible with your style, if you *don't care* about the hardware, to
produce a purely combinatorial path from input to output also depending
on decodes of the states without realizing it. That circuit will be
subject to glitching which may or may *not* show up in simulation.

No, you won't change my point of view because I have looked at yours and
found it wanting, no, I have found it ignoring the facts of hardware
design.

This is what you say, not me.

To quote you from above in the very post I am replying to...

"> Why should I care?"

In my case, area is not an issue and timing...well I can argue that if I
half the clock rate I still get what I need (I'm only too late in the
project phase to debate about the system clock rate!).

Having said that, my code needs to be ported and extended on different
FPGAs and my pure goal is readability. Writing the building blocks
(procedures) to allow a more complex functionality to be added later is
more important than your acclaimed inefficiency.

Yes, you talk about readability but you have not shown anything
"unreadable" about using signals or *not* glomming all the design into
one process.

why are you not sure? What is your point in doubting on this?


When latency *is* a problem than you're overall speed starts to suffer
since you cannot pipeline your design.

Yes, what is your point? You have said you don't try to control the
hardware with your coding style, so you don't have control over any of
this.

While counting how many clock cycles there are between two operations
make sense (latency), I do not see what sense makes doing the operation
at the 4302423th clock cycle vs 4302424th, but again it all depends on
the specs.


Why you keep saying I'm using the 'next state'? A synchronous flop
sensitive to a clock edge can *only* be sensitive to values from the
past. If you manage to get it to be sensitive to values from the future
I'll be interested to see it.

Much of the logic generated by your design will depend on the "next
state" logic of any variable that has been updated before the one being
assigned. If you don't understand that you don't understand variable.

It's a one process only, every register only reacts on a clock edge, the
value of a state depends only on the value of a combination of registers
which have been updated in the previous clock, certainly not in the next
clock cycle.

But as you have observed, variables in a process can generate
combinatorial logic and that is what an updated variable has done.

You are entitled to /believe/ that, I normally verify what I say with a
test and if it proves me wrong or right than there's nothing else I need
to believe.

Ok, so take a look at your synthesis result. One of two things will
result from the code you have described. If A is updated before B and B
depends on A, then either B will depend on the inputs to the A register
or B will duplicate all the logic that was generated for the A register.
You have the code, you have the tool, let us know how it works out.

I don't wish to continue to discuss this further. I believe I have
completed all the explanations of my points. But I would be interested
in seeing the results of your synthesis.
 
A

Andy

Your search does not end at the end of a process (or entity) just because
you use a variable. Consider the following simple statement added within a
process where 'xyz' is the variable:
some_sig <= xyz;
By your reasoning, you would not need to verify the impact of 'some_sig'
since 'xyz' is a local variable and cannot escape. That reasoning is
incorrect.

By gosh, you're right, KJ!

Whoah! This is an even bigger problem than we thought: local signals in an architecture suffer the same exact fate when assigned to a port (gasp)!

Thanks to your enlightenment, we should use only one huge entity/architecture and skip all this useless hierarchical encapsulation window-dressing, to nip this problem in the bud!



Seriously, exporting a variable by assignment to a signal is just another of the variable's "uses" that must be considered when modifying the variable.

Andy
 
K

KJ

By gosh, you're right, KJ!

Whoah! This is an even bigger problem than we thought: local signals in an architecture suffer the same exact fate when assigned to a port (gasp)!

Glad I could help clear this up for you Andy.
Thanks to your enlightenment, we should use only one huge entity/architecture and skip all this useless hierarchical encapsulation window-dressing, to nip this problem in the bud!

Note that you are on the only one in this thread that has suggested "huge entity/architecture" or "skip all this useless hierarchical encapsulation" so on this point you're nipping your own bud.
Seriously, exporting a variable by assignment to a signal is just another of the variable's "uses" that must be considered when modifying the variable.

Thanks for the update Captain Obvious. Report back soon, love to hear from you.
 
M

Mike Treseler

I prefer to concatenate blocks of state machine update code for multiple machines with one state variable per block.

-- Mike Treseler
 
A

alb

Hi Mike,

I prefer to concatenate blocks of state machine update code for
multiple machines with one state variable per block.

how do you prevent state machines not to 'step on each other toes'?
I had three state machines with three state variables, but living in one
procedure only I found myself 'tempted' at changing a state variable
from within another state machine logic.

Being very skeptical about my rigorousness, I waved this problem
separating the fsms in three different procedures with state variables
passed through parameters called in the same way as the global variables
[1] but with different type (in or inout) for each fsm. The level of
separation I achieve is good enough, with a minimal overhead.

[1] the variables are locally scoped to the process but, being the
process the only statement in the architecture, they act as if they were
'global' in the architecture scope.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top