Closed cbatten closed 3 months ago
Hi! Great to hear from you :)
In PyRTL reset exists outside of the signal set available for direct control by the user (mostly because we wanted to be clearly separate it from logic -- both so as to not confuse the tools but also so beginners are not tempted to be "creative" with reset which leads to all sorts of problems). If you assume synchronous reset and that every register is properly coded with a reset (which is the verilog that pyrtl should generate by default) there are couple ways to handle this in pyrtl simulation.
1) You can just do multiple simulations (which is usually what we do). A refactored version of the above code with simulation might look like the following:
import pyrtl
def TopModule( top_in, top_out ):
assert top_in.bitwidth == 8, 'top only works for bitwidth 8'
reg_out = pyrtl.Register(8)
reg_out.next <<= top_in
top_out <<= reg_out + 1
top_in = pyrtl.Input(8,'top_in')
top_out = pyrtl.Output(8,'top_out')
TopModule( top_in, top_out )
sim1 = pyrtl.Simulation()
sim1.step_multiple({'top_in': [0,1,5,8,8,9,10]})
sim2 = pyrtl.Simulation()
sim2.step_multiple({'top_in': [4,3,2]})
sim1.tracer.render_trace()
sim2.tracer.render_trace()
If you really want to simulate only the registers getting reset leaving memory blocks in place (as should be the case for FPGA with synchronous reset) it is pretty easy to just reach into the simulation and set the register next values to anything that you want. Here is some code that does that, using the default register values assigned to the registers along with the simulation:
import pyrtl
def TopModule( top_in, top_out ):
assert top_in.bitwidth == 8, 'top only works for bitwidth 8'
reg_out = pyrtl.Register(8)
reg_out.next <<= top_in
top_out <<= reg_out + 1
top_in = pyrtl.Input(8,'top_in')
top_out = pyrtl.Output(8,'top_out')
TopModule( top_in, top_out )
def reset_registers(simulation):
block = simulation.block
for reg in block.wirevector_subset(pyrtl.Register):
reset_value = reg.reset_value if reg.reset_value else 0
simulation.regvalue[reg] = reset_value
sim = pyrtl.Simulation()
sim.step_multiple({'top_in': [0,1,5,8,8,9,10]})
reset_registers(sim)
sim.step_multiple({'top_in': [11,12,13]})
sim.tracer.render_trace()
I have not thought deeply about the code above and if it covers all the cases it needs to (it should get all the registers and reset the in the same way as the verilog code, but it might mess with assertions or the jit-based simulators). Perhaps it is time to revisit reset semantics -- if there was a use case that multiple simulation does not cover easily we can certainly consider adding it.
OK ... this is kind of what I thought. I am experimenting with a variety of different Python-embedded DSLs and trying to create a unified way to test components each written in a different Python-embedded DSL. Some of my tests test reset behavior (i.e., start the simulation, apply some test inputs, verify the test outputs, reset the component, apply some inputs, verify the outputs) ... I think for now I will just have to skip these tests when using PyRTL ... thanks for the quick feedback!
Hi PyRTL team! Long time lurker, first time poster ... Is there a way to get access to an explicit reset signal at the toplevel of a PyRTL component?
Let's say I have this Verilog module:
I want to model something equivalent in PyRTL so I came up with this:
I can simulate this fine and
reg_out
is correctly reset to zero at the beginning of the simulation, but how do I toggle the reset signal in the middle of the simulation? Is there a way to explicitly write the reset port in PyRTL?