Forum Discussion
17 Replies
- Altera_Forum
Honored Contributor
I think you want the C2H feature where C is compiled to a hardware implementation. Search C2H on the forums and Altera site.
Bill - Altera_Forum
Honored Contributor
Hi Bill.. Thanks for reply... Erm.. I am not using C2H compiler... What I mean is after my SOPC system is build where custom peripheral had been added, when i write my program in the Eclipse using C code, how should i call my peripheral? Where can I find those names or command?
- Altera_Forum
Honored Contributor
Any information passed to the software environment accessible from C that are generated from SOPC are stored in system.h. Most C files will# include system.h to get the definitions for all of the components in the SOPC design. What is in system.h for your peripheral depends completely on the design of the peripheral. At a minimum you will have the base address. I would think you need to write a HAL (API) layer to read/write the peripheral to get it to do something and maybe to return a result. This is probably done with IORD and IOWR C macros to make your peripheral functional.
Bill - Altera_Forum
Honored Contributor
I am confused.... In my thought, i expect the HAL are auto generated... Isn't that so? If i going to write myself, is there any resources that i can refer to?
- Altera_Forum
Honored Contributor
You said "custom peripheral". How can the HAL shipped with NIOS II know what the peripheral is or does? There is a HAL for all devices in SOPC that come from Altera. Anything else in a SOPC design is custom - both hardware and the HAL are user-provided.
Bill - Altera_Forum
Honored Contributor
I see.... Thank you very much for your help. I will look into customs HAL for more detail. Is there any resources that you can recommend me to?
- Altera_Forum
Honored Contributor
My thinking is most peripherals contain one or more registers (addresses) that you write to change the hardware and read to get the result. We have an internet checksum hardware module in SOPC. We write the base address to checksum to a register and the size in bytes to another register. That second write kicks off the hardware loop to read and checksum. A register is read until the hardware is done - the hardware sets a "done" bit. Then we read a second register which contains the internet checksum.
Our HAL for this was imply an H file with the function: u16 CalcInternetChecksum(u8 *buffer, u32 length); And we use a C function that writes and reads the registers per the above description. We simply used IOWR and IORD to the# define of the BASE address in System.h (which is the peripheral name). System.h has something like:
And our H file also has# defines which are custom register offsets from the base address of the peripheral.# define INTERNET_CHECKSUM_0_BASE 0x04001000
Our hardware designer defined in his Verilog code these offsets (which are 32-bit registers). For example, this is an example checksum function:# define CHECKSUM_ADDR 0 // start addr# define CHECKSUM_LEN 1 // length# define CHECKSUM_DONE 2 // non-0 when done, 0 otherwise# define CHECKSUM_RESULT 3 // checksum result
If the base address changes in SOPC, this code will adjust to that. If the designer were to change the register offsets in the Verilog, then *I* would have to update the H file that contains those# defines. The only thing SOPC did for me was to export the base address into System.h. That's all I need from it to write the rest of this simple HAL. I hope this example is helpful! Billu16 CalcInternetChecksum(u8 *buffer, u32 length) { IOWR(INTERNET_CHECKSUM_0_BASE, CHECKSUM_ADDR, (u32) buffer); IOWR(INTERNET_CHECKSUM_0_BASE, CHECKSUM_LEN, length); while(IORD(INTERNET_CHECKSUM_0_BASE, CHECKSUM_DONE)==0) ; // Loop til done return IORD(INTERNET_CHECKSUM_0_BASE, CHECKSUM_RESULT); } - Altera_Forum
Honored Contributor
There are multiple ways to do this depending upon your HDL module. You can include your own module as a custom instruction in the SOPC Builder, as you've suggested. A simpler method would be to interface with the PIO ports. This would require instantiating your module in the high-level HDL file in Quartus, then connect your Nios2 PIO ports to your module.
For example, if you have a Verilog module that outputs a single number as a result of two inputs, simply generate 3 PIOs in your SOPC builder and connect. Your Nios program would write a number to each output PIO, then read from the input PIO after a minimum timing requirement. On the other hand, if your module requires a large amount of data stored in SDRAM (i.e. computing an md5 hash), then using the PIOs might not be such a good idea since they won't have access to the Avalon-MM bus. A 3rd method would be to create your own Avalon-MM component, which would require the most amount of programming. For what it's worth, I haven't had a good experience using Custom Instructions on anything a PIO interface couldn't easily handle. -J - Altera_Forum
Honored Contributor
--- Quote Start --- There are multiple ways to do this depending upon your HDL module. You can include your own module as a custom instruction in the SOPC Builder, as you've suggested. A simpler method would be to interface with the PIO ports. This would require instantiating your module in the high-level HDL file in Quartus, then connect your Nios2 PIO ports to your module. For example, if you have a Verilog module that outputs a single number as a result of two inputs, simply generate 3 PIOs in your SOPC builder and connect. Your Nios program would write a number to each output PIO, then read from the input PIO after a minimum timing requirement. -J --- Quote End --- Hi gaudetteje, I am trying your method of using 3 PIOs in SOPC Builder to do a simple calculation in hardware from numbers coming from NIOS. I initially tried to do a sum of products on two arrays of integer but I could not get anywere and so I decided to start with a basic addition of two numbers. See my original forum post: http://www.alteraforum.com/forum/showthread.php?t=29030 So now my verilog module is:
I've declared the input/output ports as in my other post, and added these lines in the C code:module add_two ( // Inputs line_1_in, line_2_in, // Output result_out ); //Port Declarations // Inputs input line_1_in; // 8 bit value input line_2_in; // Output output result_out; // assume 8 bit assign result_out = line_1_in + line_2_in ; endmodule
Questions: - How do I instantiate that add_two.v module in the top level .v file? - How I do make the add_two.v module accept the data from the NIOS processor through the PIOs and return a value again? - Is the use of pointers correct? I saw in another posts people suggesting to use IORD/IORW but I am not too sure how to do that. Any help is appreciated.int line1 = 3; int line2 = 4; int store_val; volatile int * line_1_ptr = (int *) 0x08200000; // Port_in_1 address volatile int * line_2_ptr = (int *) 0x08200010;// Port_in_2 address volatile int * result_back_ptr = (int *) 0x08200020;// Port_out_result *line_1_ptr = line1; *line_2_ptr = line2; store_val = * result_back_ptr; - Altera_Forum
Honored Contributor
I'll need to look at my code to give you a more detailed answer. Here's a quick response that may address some of your questions.
1- I'll look at my code tonight for an example to post. 2- Assuming your add_two.v module runs asynchronously (it is if you're not using a clock), then you need to determine the worst case latency in the calculation. If your clock period is 20ns, but your computation time is 45ns, then you'll need a NOP or pause instruction for 2 additional cycles before you can read the result. The easiest way to compute an entire array would be one byte (or word) at a time using the PIO. The Nios CPU would iterate over each index in the arrays. Write a number to PIO1, write a number to PIO2, then read from PIO3 when the computation is done. As I've said, this may take more than one clock cycle. Also, you would not be taking advantage of parallelism this way, so a custom instruction or Avalon slave component might be necessary for your speed requirements. It's always best to start simple and work your way up. 3- Look in your system.h file or possibly another included header. You'll see a# define for IORD and IORW. Altera just uses these# defs for a shortcut, but if I remember correctly they are merely pointers to your PIO registers hardware address. One other comment - you should probably take advantage of the data types defined in alt_types.h. If your C code is using 32-bit ints, you're writing a 32-bit number to an 8-bit register. This could be causing memory overflow issues if you have another register at the next memory location. I would need to refresh my memory, but isn't the Avalon-MM a 16-bit addressable bus? -J