The execution of an Origen simulation is fully controlled by Origen/Ruby, this means that if you insert a regular Ruby debugger breakpoint into your application code then you can step through the simulation in real time.
This guide describes some features that are useful for interacting with the DUT from a simulation breakpoint, or when running an interactive ad-hoc simulation from the console.
When a simulation is running most of the communication is one-way, Origen tells the simulator what to do, and for performance reasons there is no handshake between Origen and the simulator at every instruction. Instead, Origen fires off instructions into a buffer, the simulator executes them as fast as it can, and then Origen periodically waits for the simulator to catch up if it is running too far ahead.
If you have entered a breakpoint and you suspect that the simulator may be still catching up, you can run:
When that method returns you are guaranteed that the simulator is at the same point.
Note that most of the time you will not need to do this manually since Origen will automatically sync up for any operation that involves reading data from the simulation, e.g. peeking or reading registers.
If you have a wave viewer open during the debug session it may still look like the simulation is running behind, or the wave viewer may appear to hang if you have tried to refresh it. This is because the simulator is buffering output that has yet to be written to the wave dump.
You can force it to flush the buffer and update the wave viewer by running:
Note that flushing will internally call a
sync_up so you don’t have to do both of these manually.
tester.simulator.poke are available for reading and writing values
to internal DUT nets respectively.
See the section on Creating Simulation-Only Assertions for more details on these.
Referencing a register from the console will show you what Origen thinks the register currently contains:
dut.my_block.my_reg => 0x10008000 - :my_reg =============================================================================================================== │ 15 │ 14 │ 13 │ 12 │ 11 │ 10 │ 9 │ 8 │ │ d[15:8] │ │ 0x0 │ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ │ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ d[7:0] │ │ 0x0 │ └─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘
However, this may not be what the simulation currently reflects. To see what the simulation holds, call
on the register:
dut.my_block.my_reg.sync => 0x10008000 - :my_reg =============================================================================================================== │ 15 │ 14 │ 13 │ 12 │ 11 │ 10 │ 9 │ 8 │ │ d[15:8] │ │ 0x8E │ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ │ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │ │ d[7:0] │ │ 0xFF │ └─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘
A convenience API exists for this by appending
! to the register name:
Note that this works by firing off a conventional
read_register request to your DUT model/controller.
That means that it should work for breakpoints in the majority of application code, however if you have stopped it or stepped into a place in low-level code, such as in the middle of a prior transaction, then this feature may not work.
If you have just written to a register, it may kick off some operation within the DUT and time (clock cycles) will be required before you will be able to observe the response.
It is important to understand that the simulator is also paused during a breakpoint and therefore simulation time is not continuing to run while you are at the console.
Simulation time can be advanced by calling the usual
tester.wait API, however these convenience APIs exist for advancing
time during a debugger breakpoint (and they can also be used in source code if you wish):
10.cycles 10.ns! 10.us! 10.ms! 10.s!
Note that 10 is just used as an example here, you can apply any number that you want.
You can query the current error count by running:
tester.simulator.error_count # => 0