If you are wondering about how the <= operator works; it is what is called a 'nonblocking assignment.' What this means is that the left hand side of all of the <= are performed for a particular event (e.g. rising clock edge) and then once those are all evaluated, the result is placed in the output. This allows you to write shift registers without temporary variables. None of the values change until the left hand calculations are completed, then the results are moved over to the right hand side. It is generally not a good idea to use nonblocking assignments for combinatorial logic. Generally they are only used to create latches and registers and you use regular blocking assignments for combinatorial logic. When synchronized with a clock signal, you can generally consider <= operations to be D flip-flops that sample the input and transfer it to the output atomically on a single clock edge.
'Race conditions' where intermediate indeterminate results appear on the outputs of combinatorial functions are hard to avoid and they can depend greatly on how the design is actually implemented on an ASIC or FPGA. However, most designs are synchronous and so as long as the output settles within one clock period this is not a problem. There are tools that can check the timing performance of a design to check all of the path delays to ensure that the results will always be valid for a given clock frequency, but this is highly dependent not on the actual HDL code but on the way the design is placed and routed.
Synthesizers (not compilers!!!!) will generally perform optimization on combinatorial logic. There are limits to how much the synthesizer can do (e.g. it will not re-architect your system) so you have to know more or less how it will end up being implemented. If you're working on an FPGA, generally the synthesis and place and route will pack any logic function that fits onto LUTs. So if you can separate out a single logic function with up to 4 inputs and 1 output, this will end up on a single LUT and the only delay that matters is the propagation delay of the LUT, which is the same for all of its inputs. In the case of your example function, both pieces of code may be implemented identically on one LUT with three inputs and one output.
It comes back to draw the picture of what you proposed and then think about the implications.
Rising_edge has a special meaning. It designates the signal that connects to the clock pin of a flip-flop.
First consider signals that come from the output of regular logic. These are not suitable as clocks because they can glitch. In old board designs, we were able to remove glitches by creating logic with redundant terms, however, in FPGAs and ASICs we generally do not know if the target implementation will glitch or not. In addition, synthesis tools work hard to remove redundant logic - yes we can stop them from doing that, but no it is not fun. In addition, clocks generated off of logic have poor timing characteristics (delays, skew, ...). The old board designs were slow, so this wasn't too bad.
Now consider signals that come from the output of another flip-flop. Historically board designs did use these as clocks. We don't do this so much in ASIC and FPGA design. One reason is the design is considerably larger and the timing analysis becomes more challenging. Another reason is that we want to minimize the number of clock domains as any clock domain crossing must be done properly or it is problematic.
Generally in ASIC and FPGA designs, we try to minimize the number of clock domains. We try to keep good skew control of the clocks we do have - hence, we do not gate (add logic including inverters) to the clocks unless we are using a methodology that supports this.
In an FPGA, generally this means we are using a clock wizard or instantiating a vendors clock block. Those that know me may be giggling at that as my usual answer is write the code, wizards are evil (because the lock you into a particular vendor).
Best Answer
No, they are not exactly equivalent. The first variation
only works correctly if the previous state of the clock was in fact '0'. This works fine in most cases, but won't catch unusual cases, such as when the previous state was 'U', 'W', 'X' or 'Z'.
The second variation uses
rising_edge()
1, which specifically checks whether the previous state was '0' or 'L' and the new state is '1' or 'H'.1 You can see the actual definition on Stack Overflow