-
Notifications
You must be signed in to change notification settings - Fork 288
[1/3] Add external models to string_ptr; add byte_vector* as an alias #507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@kraigher, I think that the most important part to understand this PR is https://github.com/dbhi/vunit/blob/ext-strings/vunit/vhdl/data_types/src/string_ptr_pkg-body-200x.vhd#L56-L154. Precisely, https://github.com/dbhi/vunit/blob/ext-strings/vunit/vhdl/data_types/src/string_ptr_pkg-body-200x.vhd#L65-L72: type ptr_storage is record
id : integer;
ptr : integer;
eptr : integer;
ids : storage_vector_access_t;
ptrs : vava_t;
eptrs : evava_t;
end record;
When the user uses As a result, each time |
kraigher
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pull request does not contain any testing that the external mechanism works creating a technical debt.
The fact that all the existing tests pass is a proof that Nonetheless, the I must ask for some trust here. |
|
If the example serves as the test of id != 0 I would like to include it in this PR. |
It is added now.
|
523d5df to
5a27188
Compare
kraigher
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have looked through this again and found some issues. I will look further after they are fixed. Sorry for this taking such a long time but you are trying to change a core data type in VUnit which requires a lot of care.
43e7f86 to
351b301
Compare
|
@kraigher, I think I addressed all of the suggested changes. Let me know when you have another look at it. |
|
Ok I will look again. By the way I though the integer vector length -> len revert would become a separate PR. It would have been cleaner as that could be merged on its own. |
I BTW, regarding this PR, do you think it is worth having separated |
07420e0 to
fa5d6ed
Compare
b175a0a to
ed75c87
Compare
| impure function new_string_ptr ( | ||
| length : natural := 0; | ||
| mode : storage_mode_t := internal; | ||
| id : integer := 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume id=0 means automatic id assignment. This is assumed with internal string. Maybe an check is needed that is it 0 when it cannot be a custom id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really. Note that this id is NOT the same id that was in the codebase until 6 months ago. That was renamed to ref: https://github.com/VUnit/vunit/blob/master/vunit/vhdl/data_types/src/string_ptr_pkg.vhd#L20 and https://github.com/VUnit/vunit/blob/master/vunit/vhdl/data_types/src/integer_vector_ptr_pkg.vhd#L21.
The mechanism to share buffers between C and VHDL is a char* [], i.e. an array of pointers to an arrays of chars. This id is used to decide which of those arrays of chars corresponds to a string in VHDL. See examples/vhdl/external_buffer/src/main.c:
- If mode is extacc, VHDL will execute
get_string_ptr(id)to retrieve that pointer address. - If mode is extfnc, VHDL will pass the id in each call to
write_charorread_char.
In this example, using write_char (mode extfnc) is equivalent to VHDL writing directly with mode extacc. However, this is only because of the specific C implementation of write_char. In a practical example write_char is expected to do some more complex task, such as sending data through HTTP. That's where the id is handy.
When mode is internal, field id is not used at all.
Nonetheless, ref still exists. Each string, no matter the mode, has a ref; it is assigned automaticallly, as it has always been. See:
vunit/vunit/vhdl/data_types/src/string_ptr_pkg-body-200x.vhd
Lines 131 to 158 in ed75c87
| case mode is | |
| when internal => | |
| st.ids(st.id) := ( | |
| id => st.ptr, | |
| mode => internal, | |
| length => 0 | |
| ); | |
| reallocate_ptrs(st.ptrs, st.ptr); | |
| st.ptrs(st.ptr) := new vec_t'(1 to length => value); | |
| st.ptr := st.ptr + 1; | |
| when extacc => | |
| st.ids(st.id) := ( | |
| id => st.eptr, | |
| mode => extacc, | |
| length => length | |
| ); | |
| reallocate_eptrs(st.eptrs, st.eptr); | |
| st.eptrs(st.eptr) := get_ptr(id); | |
| st.eptr := st.eptr + 1; | |
| when extfnc => | |
| st.ids(st.id) := ( | |
| id => id, | |
| mode => extfnc, | |
| length => length | |
| ); | |
| end case; | |
| st.id := st.id + 1; | |
| return st.id-1; |
Let's suppose we want to use four strings:
- internal
- extacc with id 0
- internal
- extfnc with id 1
st.ids st.ptr st.eptr
string0 0 0
string1 1 0
string2 2 1
string3 3
So,
st.idsis an array ofrefthat contains four entries, one for each string.st.ptris the array of refs/pointers to internal strings (this is the element that has always existed, everything else is wrapped around it), and contains two entries.st.eptris the array of refs/pointers to extacc strings (idis used to get_string_ptr once only).
As a result:
st.ids(0).id is 0 (index to read/write from/to st.ptr)
st.ids(1).id is 0 (index to read/write from/to st.eptr)
st.ids(2).id is 1 (index to read/write from/to st.ptr)
st.ids(3).id is 1 (id to read/write through read_char and write_char)
Maybe I am overusing the name id? Currently, it is:
- A parameter for extacc to get the pointer from C.
- A parameter for extfnc to pass to read_char/write_char.
- The name of the field
st.ids, which contains a number (id) for each string. - The name of field
st.ids().idwhich contains a number representing either:- The corresponding index in
st.ptr. - The corresponding index in
st.eptr. - The
idparameter used when creating an extfnc string.
- The corresponding index in
EDIT
After reading this, I think that it might be easier to understand #507 (comment). I feel that it should be possible to merge st.ptr and st.eptr in a single array. But VHDL seems to fight against me doing it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I understand a bit better, but it still means it is user error to call the function with internal and an explicit id either by name of position?
-- Case 1
new_string_ptr(length, mode => internal, id => 1) -- Not valid
-- Case 2
new_string_ptr(length, mode => internal, id => 0) -- Also not valid
-- Case 3
new_string_ptr(length, mode => internal) -- ValidMaybe it is not so important to check "Case 2" but "Case 1" could easily give an error which might help debugging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I'd say that such a test existed: id /= 0 is not supported with mode internal. Maybe I unwantedly dropped it during some rebase/modification. Let me check.
BTW, I'm also understanding and having a look at the add_builtins comment above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added an assertion for case 1. Note that case 3 defaults to case 2. Therefore, we have no mechanism to tell them apart. Should the default of id be some non-supported value, we could identify case 2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now:
- I moved
index_ttotypes_pkg. - I renamed
idfields toeidandidx, to make it easier to tell them apart. eidis now of typeindex_tand it defaults to-1.- Assertions are added to detect cases 1 and 2, and also when extacc or extfnc are used without providing
eid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kraigher, shall I add tests for these assertions? If so, do they fit in vunit/vhdl/data_types/test/tb_byte_vector_ptr.vhd?
1143bb3 to
614bdf1
Compare
a2879d0 to
fe81505
Compare
LarsAsplund
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with these changes now
🚀🚀🚀 However, let's not merge for now. After lunch, I will re-read all the comments in this issue again, to ensure that me/we are not missing anything. I will also add some further tests (e.g., to use different Thanks for your support @go2sh. Much appreciated. |
|
Awesome work in total (your PR series), this will rock. A did a quick test on my setup and seams to work fine, but I haven't checked the code in detail. Right now I use your code to get comfortable with VPI etc. |
|
I added four new files to the @kraigher, if you are ok with the status of this PR, we can merge it and move forward. |
|
I am ok with this. |
|
Now that this is merged, will In that PR, I modify |
|
The second part of this PR is still pending: #476. Here,
Note that there are other PRs in the series (such as #470 and #568). However, any of those are to be evaluated after your contributions. This is because those higher level features might be adapted/improved based on #522. |
|
The modifications to integer_vector_ptr were really only to provide consistency between the types. It's not required. I'll probably get it up and running on top of this PR and then update integer_vector_ptr after #476 |
Coming from #476. Related to #470.
In this PR, external modes are added to
string_ptr.vhdthrough VHPIDIRECT (see https://ghdl.readthedocs.io/en/latest/using/Foreign.html). With 'external mode' we mean:get/setcallback functions defined in C (or any C-alike compatible language) to interact with strings (byte vectors).char* []) can be shared between VHDL an any C-alike compatible language.The usage is as follows:
new_string_ptr(len, mode, eid, value)creates a new array of lengthlenwith modemodeand identifierid.mode = internal(default), the array is allocated in the testbench and it is initialized withvalue.mode = extfnc, the array is not allocated. When values areget/set, VHPIDIRECT functions/proceduresread_char/write_charare called.mode = extacc, the array is not allocated. A pointer is created and the value is retrieved through VHPIDIRECT functionget_string_ptr. The returned value must be a pointer to an array of typeuint8_t(size of 1 byte). When data isget/set, content is directly modified in the shared memory.Notes:
mode /= internal,valueis not used andlenis used to tell VHDL the maximum size of the external buffer. Currently, this is a fixed value, i.e., there is no 'synchronization' of this value.mode /= internal,eidis used to decide which of the shared buffers to use.In order to support using
string_ptrwith or without VHPIDIRECT, two different implementations of the external resources are provided:external_string_pkg-vhpi.vhd, declares the functions/procedures as external; therefore, C implementations must be provided.external_string_pkg-novhpi.vhddoes not declare the functions/procedures as external; C implementations are not required, but it is not possible to create vectors withmode /= internal(an assertion of level error is raised).The user needs to select whether to use external C objects. Furthermore, alternative implementions of
*vhpi.pkgsources might be provided. This is not expected to be required for most use cases, but it is supported. This is achieved through a newexternalparameter tofrom_argsandfrom_argv:None(defaults to False){'string': False}{'string': True}{'string': ['path/to/custom/file']}deallocate,reallocateandresizeare not implemented for external modes (mode /= internal). For the caseextacc, it would be easy to implement it. Since the 'connection' is a pointer, it is possible to usemallocormmapin the C implementation. Coherently, it would be possible to update the length in the VHDL model according to the actual size in the C app.However, when
extfnc, it can be complex or not possible. Sinceread_char/write_charcan be used to interact with external services/processes through pipes, sockets, packets, messages, etc., the implementation is likely to be very specific. Nonetheless, in this example the implementation can be the same for both modes.byte_vectoris added as an alias ofstring.