Using a Custom Bitfile in C Code: Difference between revisions

From Cpre584
Jump to navigation Jump to search
No edit summary
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
My current understanding is that running a routine on the coprocessor requires two parts:
In the simplest form, running a routine on the coprocessor requires two parts:
* A call to the '''cny_get_signature''' function to get the signature of the custom personality you created
* A call to the '''cny_get_signature''' function to get the signature of the custom personality (bitfile) you created
* A cny coprocessor funcation call (ex: l_copcall_fmt, d_copcall_fmt, etc)
* A coprocessor funcation call (ex: l_copcall_fmt, d_copcall_fmt, etc)


If you want to pass parameters to your function call, the vector adder set the standard of using an assembly file to marshal registers back and forth between the processor / coprocessor, though there may be other ways.
If you want to pass parameters to your function call, you use an assembly file to marshal registers back and forth between the processor's registers (starting at A8) and the coprocessor's AEG registers.  If you must pass a lot of data, it's better to pass a pointer to the data and allocate memory on the coprocessor board.
 
=== Reusing Code ===
Don't copy and paste your code to use with Convey; instead, use the __CONVEY preprocessor directive (the cnycc compiler always defines __CONVEY).  You can then compile the same source code with both gcc and cnycc. For example:
 
<nowiki>
  #ifdef __CONVEY
    int *bigarray = cny_cp_malloc(10000);
  #else
    int *bigarray = malloc(10000);
  #endif
</nowiki>


=== Getting the Signature ===
=== Getting the Signature ===
   cny_image_t       sig2;
The standard way to get a signature is using:
  cny_image_t        sig;
<nowiki>
   cny_image_t sig1, sig2;
   int stat;
   int stat;
   if (cny_get_signature)
   if (cny_get_signature)
     cny_get_signature("your custom personality name", &sig, &sig2, &stat);
     cny_get_signature("your personality name", &sig1, &sig2, &stat);
   else  
   else  
     fprintf(stderr,"ERROR:  cny_get_signature not found\n");
     fprintf(stderr, "ERROR:  cny_get_signature not found\n");
</nowiki>
 
* '''stat''' returns 0 on success
* '''sig1''' is required, and contains a 64 bit signature for your custom bitfile/personality/AE.
* '''sig2''' is not used, but may have use in the future.


=== Allocated Memory on the Coprocessor Board ===
=== Allocated Memory on the Coprocessor Board ===
System memory and memory used for the coprocessor are physically separate.  In the example C file, function calls such as '''cny_cp_malloc''' and '''ny_cp_posix_memalign'''.
System memory and memory used for the coprocessor are physically separate.  In the example C file, function calls such as '''cny_cp_malloc''' and '''ny_cp_posix_memalign''' are used to allocate memory on the coprocessor.


See: [[Media:ConveyProgrammersGuide.pdf | Convey Programmers Guide (.pdf)]] - Chapter 9
See: [[Media:ConveyProgrammersGuide.pdf | Convey Programmers Guide (.pdf)]] - Chapter 9
Line 21: Line 39:
=== Making a Coprocessor Call ===
=== Making a Coprocessor Call ===
The vector adder example uses:
The vector adder example uses:
  act_sum = l_copcall_fmt(sig, cpVadd, "AAAA", a1, a2, a3, size);
  act_sum = l_copcall_fmt(sig1, cpVadd, "AAAA", a1, a2, a3, size);
 
The first two arguments are always (1) the bitfile signature and (2) a assembly function name.  The third argument lists the type and number of optional arguments that are passed and whether the get stored in the application hub's A or S registers.  For example, "AAAA" means there are 4 long (64 bit) variables that are stored starting in register A8; suitable for the address of a location in the coprocessor's memory system.
 
In this case, the 'l' at the beginning of l_copcall_fmt means the return type is a long (64 bits).  Other return types can be used:
* extern float f_copcall_fmt(cny_image_t,float(*func)(void),char*, ...);
* extern double d_copcall_fmt(cny_image_t,double(*func)(void),char*,...);
* extern int i_copcall_fmt(cny_image_t,int (*func)(void),char*, ...);
* extern long l_copcall_fmt(cny_image_t,long (*func)(void),char*, ...);
* extern void copcall_fmt(cny_image_t,void (*func)(void),char*, ...);
* extern void* v_copcall_fmt(cny_image_t,void*(*func)(void),char*, ...);
 
In addition to using A's for the third argument, you may use:
* 'a' pass a 32 bit quantity in an A register
* 'A' pass a 64 bit quantity in an A register
* 's' pass a 32 bit float quantity in an S register
* 'S' pass a 64 bit double quantity in an S register
* 'l' pass a 32 bit quantity in an S register (lower-case L)
* 'L' pass a 64 bit quantity in an S register
 
The first value loaded into an A register is loaded into A8, the second into A9, …
 
Similarly, the first value loaded into an S register is loaded into S1, the second into S2, …
 
See page 122 (Appendix G) of the Programmer's Guide.
 


In this case, the l at the beginning of l_copcall_fmt means the return type is a long (64 bits).  The first two arguments are always (1) the bitfile signature and (2) a assembly function name.  The third argument lists the type and number of optional arguments that are passed (starting at register A8).  For example, "AAAA" means there are 4 long variables passed to the coprocessor call.


== References ==
== References ==
* [[Media:ConveyPDKReferenceManual.pdf | Convey PDK Reference Manual (.pdf)]] - Appendix D
* [[Media:ConveyProgrammersGuide.pdf | Convey Programmers Guide (.pdf)]] - Chapter 9 and Appendix G
* [[Media:ConveyProgrammersGuide.pdf | Convey Programmers Guide (.pdf)]] - Chapter 9 and Appendix G

Latest revision as of 00:57, 13 September 2012

In the simplest form, running a routine on the coprocessor requires two parts:

  • A call to the cny_get_signature function to get the signature of the custom personality (bitfile) you created
  • A coprocessor funcation call (ex: l_copcall_fmt, d_copcall_fmt, etc)

If you want to pass parameters to your function call, you use an assembly file to marshal registers back and forth between the processor's registers (starting at A8) and the coprocessor's AEG registers. If you must pass a lot of data, it's better to pass a pointer to the data and allocate memory on the coprocessor board.

Reusing Code

Don't copy and paste your code to use with Convey; instead, use the __CONVEY preprocessor directive (the cnycc compiler always defines __CONVEY). You can then compile the same source code with both gcc and cnycc. For example:

  #ifdef __CONVEY
    int *bigarray = cny_cp_malloc(10000);
  #else
    int *bigarray = malloc(10000);
  #endif

Getting the Signature

The standard way to get a signature is using:

  cny_image_t sig1, sig2;
  int stat;

  if (cny_get_signature)
    cny_get_signature("your personality name", &sig1, &sig2, &stat);
  else 
    fprintf(stderr, "ERROR:  cny_get_signature not found\n");

  • stat returns 0 on success
  • sig1 is required, and contains a 64 bit signature for your custom bitfile/personality/AE.
  • sig2 is not used, but may have use in the future.

Allocated Memory on the Coprocessor Board

System memory and memory used for the coprocessor are physically separate. In the example C file, function calls such as cny_cp_malloc and ny_cp_posix_memalign are used to allocate memory on the coprocessor.

See: Convey Programmers Guide (.pdf) - Chapter 9

Making a Coprocessor Call

The vector adder example uses:

act_sum = l_copcall_fmt(sig1, cpVadd, "AAAA", a1, a2, a3, size);

The first two arguments are always (1) the bitfile signature and (2) a assembly function name. The third argument lists the type and number of optional arguments that are passed and whether the get stored in the application hub's A or S registers. For example, "AAAA" means there are 4 long (64 bit) variables that are stored starting in register A8; suitable for the address of a location in the coprocessor's memory system.

In this case, the 'l' at the beginning of l_copcall_fmt means the return type is a long (64 bits). Other return types can be used:

  • extern float f_copcall_fmt(cny_image_t,float(*func)(void),char*, ...);
  • extern double d_copcall_fmt(cny_image_t,double(*func)(void),char*,...);
  • extern int i_copcall_fmt(cny_image_t,int (*func)(void),char*, ...);
  • extern long l_copcall_fmt(cny_image_t,long (*func)(void),char*, ...);
  • extern void copcall_fmt(cny_image_t,void (*func)(void),char*, ...);
  • extern void* v_copcall_fmt(cny_image_t,void*(*func)(void),char*, ...);

In addition to using A's for the third argument, you may use:

  • 'a' pass a 32 bit quantity in an A register
  • 'A' pass a 64 bit quantity in an A register
  • 's' pass a 32 bit float quantity in an S register
  • 'S' pass a 64 bit double quantity in an S register
  • 'l' pass a 32 bit quantity in an S register (lower-case L)
  • 'L' pass a 64 bit quantity in an S register

The first value loaded into an A register is loaded into A8, the second into A9, …

Similarly, the first value loaded into an S register is loaded into S1, the second into S2, …

See page 122 (Appendix G) of the Programmer's Guide.


References