Open lucas-rami opened 5 months ago
I confess that I have not managed to read the whole of this. Yet I would like to add a couple of comments (not necessarily in contradiction with the above): (1) I am not convinced of the usefulness or of the convenience for users to model the behaviour of components at higher levels than RTL--because this will always be in addition to RTL modelling and the consistence of the two models tricky. (2) RTL-level components do not seem exaggeratedly complex compared to other modelling except for math operations--in fact, pretty straightforward. Maybe some fast RTL simulators may be able to leverage a high-level description of math operations without gate-level implementations. (3) Fast RTL-level simulators have similar goals as this project (zero delay, binary simulation) and Verilator seems pretty strong in this arena; maybe we should think this project more in the shape of "how can we make the best use of Verilator for high-speed simulation of our dataflow circuits".
I think this sort of simulation does more or less the same thing as SystemC (Andrea mentioned the concern after the student presented the first version of the simulator).
https://github.com/accellera-official/systemc
So why not create an export-sc tool and simulate everything in SystemC?
This is a design proposal and tracking issue for the implementation of the Handshake-level dataflow circuit simulator, or Handshake simulator for short. While we already have an experimental version of this simulator on the repository, the design/implementation effort required to get it to a correct and usable state is almost equivalent to a full rewrite, therefore this issue assumes that we start from scratch.
Goal & Requirements
The goal is to give us the ability to simulate dataflow circuits from the Handshake-level IR alone, without going to RTL through the backend and then simulating the resulting circuit with a tool like ModelSim. The former offers several benefits over the latter (in no particular order).
In order to ensure the simulator's usefulness to the community, we establish a few key design requirements.
For completeness, we also list some of the features that we do not care to have in the simulator, at least at the moment.
0
and1
). For example, we will not handle undefined or high-impedance states.Implementation roadmap
In this section we try to break down the implementation of the simulator from scratch into multiple manageable steps. This will most likely be edited a lot throughout the simulator's implementation. Issues, PRs, and commits that relate to each point will be referenced here. To keep individual contributions manageable, each pull request must cover at most the content of one of the subsections below. Smaller pull requests for sub-tasks in each subsection are allowed and encouraged if they make sense from a development perspective.
Execution models
This is likely the step that requires the most careful thought and the most design effort as it is what Dynamatic users are the most likely to interact with.
I really think it is key that we get this right and make the life of the future user as easy as possible. I have some syntax is mind that I think will be very nice to work with, it is inspired by the way MLIR handles rewrite patterns. Below is some sample C++-like pseudocode for what I envision.
This time, some pseudocode inspired by how one creates operations in MLIR.
[x] Implement a few concrete execution models to gain some confidence that our design is good enough to express a range of possible RTL implementations. For example, and for each of the following categories, we could implement the execution model of one operation whose RTL implementation fits the description (533da29).
Event-driven simulation loop
Once we have execution models, we can implement the simulator's core, in charge of invoking them as needed throughout the circuit's execution to simulate all of the combinational and sequential logic.
[x] At the center of the simulator is an event-driven simulation loop, which is tasked to invoke the execution model of each operation in the IR every time there is a change in the circuit that may affect the corresponding MLIR operation's internal state or outputs. There are two slightly different types of changes to support (533da29).
The event-driven simulator may be seen as two nested loops that iterate (potentially infinitely) as long as there is a change in the circuit.
[x] Implement the "testbench wrapper" around the simulated Handshake function, which should provide input tokens to the circuit and be able to read the circuit's output tokens at the end of simulation (533da29).
[x] Test the implementation so far with very simple circuits, using as few execution models as possible (we may need to define some in addition to the one we tested with initially to simulate on semi-interesting circuits). At this point the simulation flow should work for operations whose execution models we implemented (533da29).
We should now be able to simulate using a simple API like the following.
Instrumentation capabilities
As mentioned, one of the Handshake simulator's key benefits is the ability to extract information related to the circuit's state throughout simulation.
Here are a couple attempts at defining hooks for things that a user may care about.
Writing all execution models
Finally, we will need to go through the cumbersome task of implementing execution models for all our dataflow components.