cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
vanhuong.do
Contributor
Contributor
268 Views
Registered: ‎11-06-2019

[DPU AOL] Inquiries pointer in struct DPU driver

Jump to solution

Dear expertise!

I'm working in analysis source code of DPU driver for AOL from github as link in below: 

https://github.com/Xilinx/Vitis-AI/tree/master/mpsoc/vitis_ai_dnndk_src

I'm reading source code at n2cube/src/linux/dpu_aol.c and in the function dpu_aol_read_regs it had a line code as below: 

dpu_aol_linux_t *p = (dpu_aol_linux_t *)dev;

 As I understand the struct pointer p stand for struct dpu_aol_linux_t and the pointer dev stand for struct dpu_aol_dev_handle_t and the struct dpu_aol_dev_handle_t is the sub struct of dpu_aol_linux_t. 

Could you please explain to me why do you use that line? 

Thank you so much~~~

I still not clear 

0 Kudos
1 Solution

Accepted Solutions
shirilt
Xilinx Employee
Xilinx Employee
227 Views
Registered: ‎05-15-2018

Hi @vanhuong.do 

To give a short answer as to why it is written this way -- it is to avoid passing two struct pointers, since only one pointer can do the job, and this is possible because the two struct definitions have overlapping memory.

Detailed explanation:

The dpu_aol_linux_t struct is defined as:

typedef struct {
dpu_aol_dev_handle_t device;
int fd;
} dpu_aol_linux_t;

From this, we see that the first member of this struct is again a struct of type dpu_aol_dev_handle_t. This is very crucial to understanding why the seemingly mismatched struct pointer casting works.
When a struct of type dpu_aol_linux_t is stored in memory, it will actually store a struct of type dpu_aol_dev_handle_t at the first address and an int fd in the next address. Hence, the address of the dpu_aol_linux_t
struct will be the same as that of it's first member -- the dpu_aol_dev_handle_t struct.

Thus a pointer to a struct of type dpu_aol_dev_handle_t (dpu_aol_dev_handle_t*), is in a way also a pointer to a struct of type dpu_aol_linux_t (dpu_aol_linux_t*). Now let us consider the function you were asking about:
int dpu_aol_read_regs(dpu_aol_dev_handle_t *dev, uint64_t phy_address, uint32_t *buf, uint32_t count)

The first argument being passed to this function is dpu_aol_dev_handle_t *dev. Using the above logic, the memory address contained in dev is also the same as the memory address of the struct of type dpu_aol_linux_t.
However, we cannot access elements of a struct of type dpu_aol_linux_t, using a dpu_aol_dev_handle_t*, although both these structs have the same address in memory. Hence, to access the member 'fd' from the dpu_aol_linux_t struct,
we need to explicitly cast the pointer dpu_aol_dev_handle_t*. After casting, the dpu_aol_linux_t* pointer will point to the same address as the dpu_aol_dev_handle_t *dev pointer being passed to the function. But using the new dpu_aol_linux_t* pointer
we will now be able to access the next location in memory, which is the 'fd' member of the struct. This is the reasoning behind the line -- dpu_aol_linux_t *p = (dpu_aol_linux_t *)dev;

The following is a simple demonstration of the above using a C program:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

/* Simple struct -- similar to dpu_aol_dev_handle_t */
typedef struct{
  uint32_t a;
} struct_1;

/* Composite struct containing the above struct -- similar to dpu_aol_linux_t */
typedef struct{
  struct_1 s; 
  uint32_t b;
} struct_2;

int main(void) {
  struct_1* s1 = NULL;
  struct_2 * s2 = (struct_2*)malloc(sizeof(struct_2));
  s2->s.a=1;
  s2->b = 2;
  s1 = &s2->s; // s1 points to the structure in s2, i.e. s1 is the equivalent of dev in the original code
  printf("%p\n",s1); //since s1 points to first member of s2, observe that their addresses are the same
  printf("%p\n",s2);
  printf("%d\n",s2->s.a);
  printf("%d\n",s2->b);
  printf("---After struct pointer cast---\n");
  s2 = (struct_2*)s1; //cast the pointer -- similar to dpu_aol_linux_t *p = (dpu_aol_linux_t *)dev
  printf("%p\n",s1); //Even after the cast, we can access the same values using s2. 
  printf("%p\n",s2);
  printf("%d\n",s2->s.a);
  printf("%d\n",s2->b);
  /* So if this was to be done in a function call, we could only pass a pointer to s1, and still be able to access members of struct s2. */
  return 0;
}

 Hope that helps!

---------------------------------------------------------------------------
Don’t forget to Reply, Kudo, and Accept as Solution.
---------------------------------------------------------------------------

View solution in original post

1 Reply
shirilt
Xilinx Employee
Xilinx Employee
228 Views
Registered: ‎05-15-2018

Hi @vanhuong.do 

To give a short answer as to why it is written this way -- it is to avoid passing two struct pointers, since only one pointer can do the job, and this is possible because the two struct definitions have overlapping memory.

Detailed explanation:

The dpu_aol_linux_t struct is defined as:

typedef struct {
dpu_aol_dev_handle_t device;
int fd;
} dpu_aol_linux_t;

From this, we see that the first member of this struct is again a struct of type dpu_aol_dev_handle_t. This is very crucial to understanding why the seemingly mismatched struct pointer casting works.
When a struct of type dpu_aol_linux_t is stored in memory, it will actually store a struct of type dpu_aol_dev_handle_t at the first address and an int fd in the next address. Hence, the address of the dpu_aol_linux_t
struct will be the same as that of it's first member -- the dpu_aol_dev_handle_t struct.

Thus a pointer to a struct of type dpu_aol_dev_handle_t (dpu_aol_dev_handle_t*), is in a way also a pointer to a struct of type dpu_aol_linux_t (dpu_aol_linux_t*). Now let us consider the function you were asking about:
int dpu_aol_read_regs(dpu_aol_dev_handle_t *dev, uint64_t phy_address, uint32_t *buf, uint32_t count)

The first argument being passed to this function is dpu_aol_dev_handle_t *dev. Using the above logic, the memory address contained in dev is also the same as the memory address of the struct of type dpu_aol_linux_t.
However, we cannot access elements of a struct of type dpu_aol_linux_t, using a dpu_aol_dev_handle_t*, although both these structs have the same address in memory. Hence, to access the member 'fd' from the dpu_aol_linux_t struct,
we need to explicitly cast the pointer dpu_aol_dev_handle_t*. After casting, the dpu_aol_linux_t* pointer will point to the same address as the dpu_aol_dev_handle_t *dev pointer being passed to the function. But using the new dpu_aol_linux_t* pointer
we will now be able to access the next location in memory, which is the 'fd' member of the struct. This is the reasoning behind the line -- dpu_aol_linux_t *p = (dpu_aol_linux_t *)dev;

The following is a simple demonstration of the above using a C program:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

/* Simple struct -- similar to dpu_aol_dev_handle_t */
typedef struct{
  uint32_t a;
} struct_1;

/* Composite struct containing the above struct -- similar to dpu_aol_linux_t */
typedef struct{
  struct_1 s; 
  uint32_t b;
} struct_2;

int main(void) {
  struct_1* s1 = NULL;
  struct_2 * s2 = (struct_2*)malloc(sizeof(struct_2));
  s2->s.a=1;
  s2->b = 2;
  s1 = &s2->s; // s1 points to the structure in s2, i.e. s1 is the equivalent of dev in the original code
  printf("%p\n",s1); //since s1 points to first member of s2, observe that their addresses are the same
  printf("%p\n",s2);
  printf("%d\n",s2->s.a);
  printf("%d\n",s2->b);
  printf("---After struct pointer cast---\n");
  s2 = (struct_2*)s1; //cast the pointer -- similar to dpu_aol_linux_t *p = (dpu_aol_linux_t *)dev
  printf("%p\n",s1); //Even after the cast, we can access the same values using s2. 
  printf("%p\n",s2);
  printf("%d\n",s2->s.a);
  printf("%d\n",s2->b);
  /* So if this was to be done in a function call, we could only pass a pointer to s1, and still be able to access members of struct s2. */
  return 0;
}

 Hope that helps!

---------------------------------------------------------------------------
Don’t forget to Reply, Kudo, and Accept as Solution.
---------------------------------------------------------------------------

View solution in original post