I think your model is mostly right. But, I would replace "right before the next clock edge" with "right after the registered and combinatorial signals have propagated and settled". I mean, the function is called Settle, after all...
If you have slow logic, the signals really will take that long to settle. And it will have an impact on your timing budget, and consequently the maximum clock rate.
But, on a simulation, logic is infinitely fast. Signals will settle right after the rising edge of the clock.
If you zoom-in on GTKWave, you will see no delay at all between the rising clock, and the signals changing.
So, technically, you don't have to wait until before the next clock edge. It's not wrong if you do, but you would be missing some finer points.
Here is what happens, as I understand it:
1) You just called yield.
This will cause the clock to rise.
2) Yield returns.
The time point, it's just after the clock has risen.
Registers have registered their inputs, but are still outputting their old value.
This is because flip-flops have a non-zero delay, between the rise of the clock, and the output reflecting the new value.
Since we are just after the clock has risen, this has not taken place yet.
3) We sample any signals.
As said above, signals (registered or not) will keep the values they had just before the clock edge.
It's as if the sampling point was just before the previous clock edge.
4) We change any signals we like.
Because we are already past the clock edge, we cannot influence any registered output on this cycle, even if we change their inputs.
Combinatorial logic, on the other hand, will really be influenced, on this cycle.
5) We call Settle()
The time point moves to when all propagation delays are over, when both registers and combinatorial logic had a chance to propagate and settle their final values.
6) We sample any signals, again
This time, we will finally see the new values of the registers, and any combinatorial logic that depends on them.
7) We change any signals we like, again.
Here, we have the chance to respond in the same cycle, as if we were combinatorial logic ourselves.
Hope it was clear.
(In reply to Cesar Strauss from comment #1)
> 4) We change any signals we like.
> Because we are already past the clock edge, we cannot influence any
> registered output on this cycle, even if we change their inputs.
> Combinatorial logic, on the other hand, will really be influenced, on this
> 5) We call Settle()
> The time point moves to when all propagation delays are over, when both
> registers and combinatorial logic had a chance to propagate and settle their
> final values.
rrright. i had to think about what is going on here. i can confirm that
removing Settle() from the test code, after a yield which is supposed to
perform full clock sync, results in *failure* of the test.
the only reason i can think of why that would be the case is if, inside
the FSM that creates new output on each new clock cycle, the output is
*NOT* directly from a register/latch, it is from yet more further combinatorial
logic that is created **FROM** clock-synchronised registers/latches.
consequently, although we intuitively might expect the data to be valid at
the clock, certain designs this will not be the case and it's going to be
something we seriously have to keep an eye on.
i don't know if it's just unavoidable or it's bad design practice.