combinational loops

Discussion in 'VHDL' started by alb, Sep 20, 2013.

  1. alb

    alb Guest

    Hi Rick,

    On 03/10/2013 05:24, 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...
    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.

    []
    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?
    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].

    []
    'this' or 'that' clock cycle does not really matter to me, latency apart
    I get the same throughput.
     
    alb, Oct 3, 2013
    #41
    1. Advertisements

  2. alb

    Andy Guest

    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
     
    Andy, Oct 3, 2013
    #42
    1. Advertisements

  3. alb

    alb Guest

    I forgot to add a note to my previous post.

    [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.
     
    alb, Oct 3, 2013
    #43
  4. alb

    KJ Guest

    You're missing your original point which I was responding to with this comment.
    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.
    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.
    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.
    It is a gripe of mine too, but it doesn't seem to be a tool issue that willgo away soon.
    And a good suggestion at that.
    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
     
    KJ, Oct 4, 2013
    #44
  5. alb

    alb Guest

    Hi Kevin,

    On 04/10/2013 03:10, KJ 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.

    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.

    []
    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.
     
    alb, Oct 4, 2013
    #45
  6. alb

    rickman Guest

    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.

    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.

    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.

    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.
     
    rickman, Oct 4, 2013
    #46
  7. alb

    rickman Guest

    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.
     
    rickman, Oct 4, 2013
    #47
  8. alb

    alb Guest

    Hi Rick,

    On 04/10/2013 15:19, rickman wrote:
    []
    Read from top to bottom, this may help. The synthesis tool seem to get
    it pretty straight forward.
    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.

    []
    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.
    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.
    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 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.

    []
    This is what you say, not me.
    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.
    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.
    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.

    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.
    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.
     
    alb, Oct 4, 2013
    #48
  9. alb

    KJ Guest

    On Friday, October 4, 2013 4:55:43 AM UTC-4, alb wrote:
    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.
    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.
    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.
    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
     
    KJ, Oct 4, 2013
    #49
  10. alb

    Andy Guest

    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
     
    Andy, Oct 4, 2013
    #50
  11. alb

    rickman Guest

    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?

    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.

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

    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.


    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.

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

    "> Why should I care?"

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

    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.

    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.

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

    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.
     
    rickman, Oct 6, 2013
    #51
  12. alb

    Andy Guest

    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
     
    Andy, Oct 7, 2013
    #52
  13. alb

    KJ Guest

    Glad I could help clear this up for you Andy.
    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.
    Thanks for the update Captain Obvious. Report back soon, love to hear from you.
     
    KJ, Oct 8, 2013
    #53
  14. I prefer to concatenate blocks of state machine update code for multiple machines with one state variable per block.

    -- Mike Treseler
     
    Mike Treseler, Oct 28, 2013
    #54
  15. alb

    alb Guest

    Hi Mike,

    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.
     
    alb, Oct 28, 2013
    #55
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.