Description
@LarsAsplund, @kraiger and @umarcor,
I would like to propose a broad strategy for co-simulation with VUnit. I really like what @umarcor has been working on, but I think his approach leaves most of the implementation to users. If I understand #568 correctly, users have to manually synchronize between VHDL and C/Python using clock signals run through a string_ptr
. That approach is extremely powerful and flexible, but to me, it doesn't seem very easy to use or approachable for new users.
So far, I've found VUnit to be extremely easy to learn and use, because the VHDL libraries abstract away many of the low-level details. I never even knew string_ptr_pkg
existed until I started reading the VUnit codebase out of interest. However, even with simple, easy-to-use libraries, I have struggled to convince my co-workers to learn and use VUnit. I fear it will be even harder to convince them to use VUnit for co-simulation if they have to implement most of the low-level details.
Based on the work I've already done for #521 and #522, and the discussion in #583, I would like to propose a more comprehensive approach to co-simulation. Essentially, I would like to communicate with C/Python code in the same way that I currently communicate with concurrent actors in VHDL, using messages and queues. I think this approach will require more work than what @umarcor has proposed, but I think the end result will be much more user-friendly. Furthermore, there is a lot of overlap between this proposal and my work on #521 and #522.
To support my proposal, I spent some time this past week prototyping various pieces. Here is an overview of a roadmap, as I see it:
- Implement
ext_ptr.c
andext_ptr_pkg
- Mostly complete
This library is essentially a port of string_ptr_pkg
and integer_vector_ptr_pkg
to C. It serves the same purpose in C as those packages do in VHDL. It is only responsible for providing shared memory among concurrent actors. It is not used for synchronizing between actors. I already have a complete, working implementation, with tests, here.
- Modify
string_ptr_pkg
andinteger_vector_ptr_pkg
to cast to and fromext_ptr_t
- Trivial
This change would make it possible to create instances of string_ptr
and integer_vector_ptr
in VHDL that are stored externally. This is the infrastructure for implementing external queues. Because ext_ptr_pkg
and ext_ptr.c
mimic the structure of the two VHDL ptr
packages, adding this would be trivial.
- Update
queue_pkg
to push and pop instances ofstring_ptr
rather thancharacter
, so that you can push and pop whole items - Complete
This approach is faster than the current implementation, and it is more useful, because the queue length now tells you how many items are left in the queue. #522 is a working and tested implementation. Performance comparisons are available in #521.
- Add external queues - Straight forward
Modify queue_pkg
to accept an external
option. For a given queue, if external
is true, the queue would create external rather than internal instances of string_ptr
, and it would push and pop using a C library, ext_queue.c
.
- Modify the
codec
libraries to encode all VHDL types in a binary compatible manner - Mostly complete
With this change, any VHDL type encoded into an external string_ptr
could be read directly by C code, without any decoding step. I have already done this while working on my changes for #521. I can make this code available, if you would like to see what I've done.
- Generalize the VUnit type system to make it modular and extensible - Mostly complete
This has two benefits. For co-simulation, it will set the stage for pushing and poping any VHDL type from external queues. More generally, it will allow us to create new VUnit data structures, like list_t
. It will also make it easy to extend the existing dict_t
to all types. The latter were my initial objectives in #521. As above, I have already implemented most of this. I just haven't made it public yet.
- Extend the type definitions from VHDL to C. - No progress yet
As stated above, a generic type system can be easily extended to C, which will allow users to easily read and write VHDL types encoded by VUnit. This is the last step needed for a full implementation of external queues.
- Extend the com library from VHDL to C - Prototyping complete
This is the final piece that brings the whole proposal together. With this change, we can treat external actors like any other VUnit actor. All synchronization between VHDL and C/Python can be handled with messages. I have already prototyped the actor_t
, actor_item_t
, msg_t
, envelope_t
and mailbox_t
data structures in C. With them, I demonstrated that you can add external actors, find them in VHDL, and push/pop messages (see here).
To send a message to an external actor, you simply have to create an external message that uses an external queue to store its data. The actual synchronization happens when calling the com
function notify
. When this function is called, it would call an ext_com.c
function that would run a list of C functions specified by users. These C functions would essentially act as concurrent processes do in VHDL. When run, they would check for new messages and act accordingly.
What do you think? Do you agree that this approach would be easier for users? I'm eager to work on this, but I don't want to devote more effort without buy-in from you three.