UCSBarchlab / PyRTL

A collection of classes providing simple hardware specification, simulation, tracing, and testing suitable for teaching and research. Simplicity, usability, clarity, and extensibility are the overarching goals, rather than performance or optimization.
http://ucsbarchlab.github.io/PyRTL
BSD 3-Clause "New" or "Revised" License
255 stars 78 forks source link

Checking op dependencies when only one is needed #90

Closed jemcmahan13 closed 9 years ago

jemcmahan13 commented 9 years ago

A design may have "non-register loops" that are irrelevant.

For example, the output of a mux might conditionally loop to one of its inputs, but that input is never selected at the same time the loop is active.

We might want to talk about this, since it changes the core of how the simulation is done.

The following is a (trivial and nonsensical) example that demonstrates the problem. The circuit definitely has a defined output, but the simulator throws a loop error.

from pyrtl import *

loopwire = WireVector(bitwidth=1)  # This is input 1 of the mux and will be driven by mux output                                                
inwire = Input(1)  # Input 0 of mux                                                                                                             
out = mux(Const(0), falsecase=inwire, truecase=loopwire)  # Loop exists but "doesn't matter"                                                    
loopwire <<= out

sim_trace = SimulationTrace()
sim = FastSimulation(tracer=sim_trace)
sim.step({inval: Const(0)})

One could also imagine the select input as a block input, to make the example not trivially solvable with constant propagation. In that case, the circuit might, but will not necessarily, have metastability.

jemcmahan13 commented 9 years ago

I've run into this problem a couple times before in the FunBox, but wasn't able to pin down the source of the "non-register loops;" I ended up adding new states to the control logic both times to solve it. Third time encountering it I realize pyrtl's definition of "loops" is a strict, statically detectable one, but whether or not those physical loops matter can only be decided per-cycle.

It would also mean changing how __iter__ works, since a physical loop might show up that isn't "dangerous".

jemcmahan13 commented 9 years ago

I'm also going to just point out that a proof-based system would handle this statically by just requiring you prove the loop never occurs.

Gamrix commented 9 years ago

Part of the problem is that the current simulator design (and timing analysis) relies on the notion that a loop does not exist statically to evaluate the whole block. Without this, the current simulator design cannot determine how to assign values to some of the wires. Some of the simulator problems can be solved by short circuiting (we know that the output of a and would be 0 if one of the inputs are zero, even if the other is unknown), but I don't see a good way to generally resolve this problem without resorting to a verilog esque simulator

Gamrix commented 9 years ago

Also, I would like to see an example where the current synthesis and optimization do not resolve

jemcmahan13 commented 9 years ago
from pyrtl import *

loopwire = WireVector(bitwidth=1)  # This is input 1 of the mux and will be driven by mux output                                                                                                                                              
inwire = Input(1)  # Input 0 of mux                                                                                                                                                                                                           
select = Input(1)
out = Output()
mout = mux(select, falsecase=inwire, truecase=loopwire)  # Loop exists but "doesn't matter"                                                                                                                                                   
loopwire <<= mout
out <<= mout

optimize()
#synthesize()                                                                                                                                                                                                                                 

for x in working_block():
    print x
Gamrix commented 9 years ago

I just don't see the large benefit of creating a feature that does runtime short circuiting. I can see how this can make people think that their circuits work when they have actually not tested for the time where the circuit would fail badly.

On top of this, we must note that our simulation does not really take into account all the intricacies of hardware. For example if there is an illegal state and timing delays cause actual hardware to enter this illegal state, actual hardware might exhibit behavior that would not show up in PyRTL.

A good example of this is metastability in D Flip-flops. If we had the implementation talked about above (ignoring the fact that we could still not simulate the holding of state in a D flip-flop), a pyrtl implementation as you described would in a metastable state, woud just wait for the state to no longer be metastable, whereas actual hardware would exhibit interesting behavior that could propagate through the circuit

https://en.wikipedia.org/wiki/Metastability_in_electronics

You're welcome to implement a simulator that has this short-circuiting behavior, but I would really want a lot of warnings attached to such a simulator.

timsherwood commented 9 years ago

This is a very interesting discussion, and I agree with Joseph that this is both overly conservative and something that a dependently types HDL would probably catch (neat idea!). However, I think PyRTL has always had the philosophy of not allowing all hardware designs, just the subset that we think is useful. I think that this is probably not a good design practice to allow this and also unlikely to come up in designs other than single-cycle CPUs (I am guessing that pipelines would remove this kind of stuff that is attempting to reuse components in funky ways, but I am happy to be wrong about that). Thus I am going to close this request. HOWEVER we do need to give much better feedback to the user about the loops that are messing them up -- it is not sufficient to just say "fail on loop -- figure it out turkey".