Skip to content
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

WIP: Support records in vpi #1249

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

benreynwar
Copy link
Contributor

Description

The goal is to make it possible to use cocotb with a design that uses nested records and arrays in it's ports, signals and generics. Related to issue #237.

It is a long way from being finished, but it would be useful to get some feedback. If you have the time and inclination, any comments would be appreciated.

I've added comments to the code where I have questions about how things should work.

@@ -27,6 +27,19 @@ with Grt.Vstrings; use Grt.Vstrings;
with Grt.Rtis_Utils; use Grt.Rtis_Utils;
with Grt.To_Strings;

-- Acronyms that I don't understand:
-- Rti
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rti: run time information. That's all the data emitted by translate to describe vhdl types and subtypes.

@@ -27,6 +27,19 @@ with Grt.Vstrings; use Grt.Vstrings;
with Grt.Rtis_Utils; use Grt.Rtis_Utils;
with Grt.To_Strings;

-- Acronyms that I don't understand:
-- Rti
-- Rtis
Copy link
Member

@tgingold tgingold Apr 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grt.rtis is the package that describes the rti.

-- Acronyms that I don't understand:
-- Rti
-- Rtis
-- Rtin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rti node. All the ghdl_rtin_* records defines the rti data.


-- Questoins:
-- Explanation for the Ctxt objects would be really helpful.
-- Why are they used, and what do they represent?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example for a port:
you have an rti that describes the port: its name, its type, its mode...
But you also need its address to get its value. But a port is part of an entity that can be instantiated many times. So you need the context of the port, which consists of the entity/architecture and the address of the entity/architecture instance.

-- Questoins:
-- Explanation for the Ctxt objects would be really helpful.
-- Why are they used, and what do they represent?
-- Does ghdl support a VHPI interface?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not at the C level. There is AVHPI which is inspired from VHPI but uses Ada style. But there is no C VHPI interface. Shouldn't be very hard to do, but there are very few examples.

-- Why are they used, and what do they represent?
-- Does ghdl support a VHPI interface?
-- What's the best way to test this work. Should we add
-- a cocotb dependency to the testing?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really prefer to have standalone tests. That's easier to investigate and do not depends on cocotb evolution.

when VhpiGenericDeclK =>
when VhpiGenericDeclK |
VhpiPortDeclK |
VhpiSigDeclK =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks ok.

Res := (Kind => AvhpiNameIteratorK,
Ctxt => Ref.Ctxt,
-- What does the 'N_' indicate?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the prefix for names in the vhpiHandleT. All the names in a record must be unique.

@@ -145,6 +162,8 @@ package body Grt.Avhpi is
return;
end case;
case Res.N_Type.Kind is
-- Why only Ghdl_Rtik_Subtype_Array?
-- Why not also Ghdl_Rtik_Type_Array?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, to be added ?

return;
end case;
case Res.N_Type.Kind is
when Ghdl_Rtik_Type_Record =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and also record subtypes ? :-)

@@ -184,6 +254,9 @@ package body Grt.Avhpi is
El_Type1 : Ghdl_Rti_Access;
begin
case Obj_Rti.Common.Kind is
-- Does this mean we only support scanning iterators in
-- generics. That doesn't make much sense.
-- What am I missing?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly. In VPI you can directly get the value of a vector.

-- Maybe signals are built as structures of signals,
-- but generics are raw? So signals effectively
-- contain lots of thin signal wrappers that we're
-- pointing at.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, generics contain the raw value, while signals are addresses to an internal structure.

-- An explanation of what's going on here would be really
-- helpful.
-- It looks like we're finding out the size of the structure
-- but I've failed to understand how.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah OK. So that's the for_generate_statement. There is an array containing the sub-instances, because the block can be repeated many times. So we need to update the context to point to the corresponding sub-instance.

@@ -219,11 +302,17 @@ package body Grt.Avhpi is
end if;
end;
when others =>
-- Feels like we supported a strange subset of possible types.
-- I'm curious what drove the supported features in this
-- implementation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is mainly SDF annotations + what has been asked for VPI.

-- Decrement number of elements left in iterator.
Iterator.N_Idx := Iterator.N_Idx - 1;
Error := AvhpiErrorOk;
end Vhpi_Scan_Selected_Name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks OK, but I haven't thoroughly reviewed this subprogram.

@@ -398,6 +526,7 @@ package body Grt.Avhpi is
Bt : constant Ghdl_Rtin_Type_Array_Acc :=
To_Ghdl_Rtin_Type_Array_Acc (Atype.Basetype);
begin
-- I don't understand what's happening here.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. An array type declaration like type my_vec is array (0 to 7) of bit is represented as an anonymous unconstrained array type declaration type anon_my_vec is array (integer range <>) of bit followed by a subtype declaration subtype my_vec is anon_my_vec(0 to 7). So we need to ignore the anonymous array type declaration and pretend that the subtype declaration is a type declaration.

@@ -68,7 +69,7 @@ package body Grt.Vpi is
Version : constant String := "0.1" & NUL;

-- If true, emit traces
Flag_Trace : Boolean := False;
Flag_Trace : Boolean := True;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use --vpi-trace to dynamically set this flag.

Copy link
Member

@tgingold tgingold left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments added.

@benreynwar
Copy link
Contributor Author

Awesome, thanks a bunch for the help!

@tgingold
Copy link
Member

tgingold commented Apr 19, 2020 via email

@benreynwar
Copy link
Contributor Author

I'm trying to understand the RTI structures but am having difficulty understanding what data is stored in the memory that the Loc fields point to. My understanding is that the Loc fields tell us the location of relevant data in the memory relative to the address specified by Rti_Context.Base, but I'm not sure what structure exactly is stored in this location, and how the stored data is different for the different RTI nodes.

@tgingold
Copy link
Member

tgingold commented Apr 23, 2020 via email

@benreynwar
Copy link
Contributor Author

Looking at grt-disp_rti is helping. I don't have any additional questions, and there's nothing that's worth reviewing yet. I'm just going through grt-disp_rti and making sure I understand what's going on.

@benreynwar
Copy link
Contributor Author

When a new array type is defined that binds an unbound type an anonymous RTI type object is created:

type mytype is array(natural range <>) of std_logic_vector(WIDTH-1 downto 0);

However when a new record type is defined that binds an unbound type an anonymous type is not created. Rather the information about the bounds is stored in the element node of the record.

type mytype is record
  a: std_logic_vector(WIDTH-1 downto 0);
end;

This is a bit of a pain when dealing with the subcomponents of the signal, since there is no RTI type that can be easily referred to. Instead we have to refer to the unbound type, and the bounds information. It would be much more pleasant if records created anonymous types in the same way that arrays do. Is this a change that could be limited to the RTI part of the codebase or would it be more complicated?

@benreynwar
Copy link
Contributor Author

benreynwar commented May 4, 2020

Also, the RTI tree has Ghdl_Rti_Object to represent signal/port/constant/generic but doesn't contain any more fine-grained objects to represent the subcomponents. Is this intentional so that we don't get a crazy number of objects that might effect peformance, or was it just that there was no advantage to it? Having more fine-grained objects could simplify things when dealing with records and arrays.

@tgingold
Copy link
Member

tgingold commented May 4, 2020 via email

@tgingold
Copy link
Member

tgingold commented May 4, 2020 via email

@benreynwar
Copy link
Contributor Author

My understanding is that an anonymous RTI node with kind Ghdl_Rtik_Subtype_Array is created. The Ghdl_Rtik_Type_Array with name myarr then references this anonymous subtype as it's Element.

For the myrec type no anonymous subtype array is created, rather the Ghdl_Rtik_Type_Array is used in conjunction with the bounds stored in the layout associated with the Ghdl_Rtin_Element.

The anonymous types don't show in the disp_rti dump because they are not children of any of the blocks.

@benreynwar
Copy link
Contributor Author

benreynwar commented May 4, 2020

I still don't understand why this couldn't be implemented as an anonymous subtype. Defining the bounds in the object is equivalent to defining the bounds in an anonymous subtype and then pointing the object to that subtype. I don't use much of vhdl08 so it's possible I'm missing something. I have a book on vhdl08 arriving in a couple of weeks :).

No, because the bounds may belong to the object and not to the subtype. For example: type string_acc is access string; a := new string'("Hello"); b := new string'("my world"); So a and b have two different bounds, and the number of such objects is unknown. So if we needed to always have bounds in an RTI we would have to dynamically create RTIs.

Still trying to get my head around this. In the example you gave we'll be creating RTIs for a and b. Why wouldn't it be practical to create an anonymous subtype for each at the same time?

Edit: I'm going to sleep now. Thanks for the explanations.

@tgingold
Copy link
Member

tgingold commented May 4, 2020 via email

@benreynwar
Copy link
Contributor Author

Still trying to get my head around this. In the example you gave we'll be creating RTIs for a and b. Why wouldn't it be practical to create an anonymous subtype for each at the same time?

And to store the bounds within this RTI ? The consequence is that you will have to modify the RTIs each time to assign such a variable, because you could change the bounds. But RTIs are read-only. Or having RTIs that say that the bounds are within the object ? I fear that would be much more complex or not very different from the current implementation.

I understand. The bounds are determined after elaboration and could change during runtime. I have to try to remember about non-synthesizable vhdl too :).

tgingold added a commit that referenced this pull request May 4, 2020
@tgingold
Copy link
Member

tgingold commented May 4, 2020 via email

@elgorwi elgorwi mentioned this pull request Jun 24, 2020
5 tasks
@benreynwar
Copy link
Contributor Author

I'm continuing to very slowly work on this. If anyone is impatient and would like to have a crack themselves, I won't be at all offended if you take over :).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants