Success! Subscription added.
Success! Subscription removed.
Sorry, you must verify to complete this action. Please click the verification link in your email. You may re-send via your profile.
Altera's Nios II Custom Instruction User Guide describes adding custom instructions to a Nios II processor and using them in C and assembly language programs.
You may call the custom instruction build-in functions for C in your apps. Please check the appendix B of this user guide.
int __builtin_custom_in (int n);
int __builtin_custom_ini (int n, int dataa);
The Nios II processor doesn't have an FPU, but you can direct the nios2-elf-gcc compiler to generate custom instructions in place of library calls for most floating-point operations.
Let's say that your hardware engineer has regenerated your system's Nios II processor to include a custom instruction that converts an integer into a float. He has made N, the 8-bit value that selects the custom instruction, equal to 42. When you compile your C code, add the the command-line option -mcustom-floatis=42 . Then when converting an int into a float, instead of GCC generating this Nios II assembly code
call __floatsisf
it will generate code like
custom 42, r4, r4, zero
which will execute much faster.
Here is a table of single-precision -mcustom-* options. Be aware that if you provide some functions (sin, cos, tan, atan, exp, log), GCC will require you to provide a second option before it will use these more complex hardware operations. The second option is
-funsafe-math-optimizations
This option is GCC's way of saying, "I can't imagine that your transcendental floating-point hardware is IEEE compliant, and I want you to admit this before I'll use it." The option is not required for the other operations. You'll be happy to know that nios2-elf-gcc reports a warning asking for this second option when it's been omitted but it's needed.
It also is possible for nios2-elf-gcc to support double-precision floating-point custom instructions, but the implementation is less straightforward.
The nios2-elf-gcc compiler stores double-precision floating-point variables in pairs of general-purpose registers. Since custom instructions are limited to accessing 64 bits of operands and returning 32 bits of result, double-precision floating-point operations must be provided by groups of cooperating custom instructions, which retrieve the necessary 128 bits of operands, perform the necessary operation, and return 64 bits of result. The nios2-elf-gcc compiler assumes that if your hardware engineer provides any double-precision floating-point custom instructions, he also will provide and use internal registers X and Y, as described below.
Note: X and Y refer to internal registers of the custom-instruction logic. They are not part of the Nios II ABI.
X is a 64-bit register, and Y is a 32-bit register. Both of these registers are exposed to the compiler, to any exception handler that uses double-precision floating point, and to any OS that switches context among threads that use double-precision floating point. In all but the first case, you must modify the exception handler or the OS to save and restore the contents of X and Y when necessary.
To support these X and Y registers, a custom double-precision floating-point unit must provide the following five data-movement operations as custom instructions.
-mcustom-fwrx=N:
custom N, zero, src1, src2 /* X = (src2:src1) */
Writes the 64-bit register X with the contents of general-purpose registers src1 and src2 by copying src1 into the least significant half of X and src2 into the most significant half of X.
-mcustom-fwry=N:
custom N, zero, src1, zero /* Y = src1 */
Writes the 32-bit register Y with the contents of general-purpose register src1.
-mcustom-frdxlo=N:
custom N, dest, zero, zero /* dest = X[31:0] */
Reads the least significant half of X, storing it into general-purpose register dest.
-mcustom-frdxhi=N:
custom N, dest, zero, zero /* dest = X[63:32] */
Reads the most significant half of X, storing it into general purpose register dest.
-mcustom-frdy=N:
custom N, dest, zero, zero /* dest = Y */
Reads register Y, storing it into general-purpose register dest.
To do this double-precision floating-point multiply using the registers indicated:
r3:r2 = r5:r4 * r7:r6
The Nios II compiler generates custom instructions for these operations (this isn't legal Nios II assembly language; the opcodes are just representative of the required custom instructions):
fwrx r4, r5 /* Write register X with (r5:r4) */
fmuld r3, r6, r7 /* Multiply, storing half of the result in r3: (r3:Y) = X * r7:r6 */
frdy r2 /* Store the other half of the result in r2: r2 = Y */
The Nios II compiler does not generate fwry, frdxlo, and frdxhi operations, but these operations must be provided so that exception handling and thread code can work correctly. (Consider the case of a context switch that occurs between the fmuld and the frdyin the example.)
Here is a table of double-precision -mcustom-* options. The custom instructions fwrx and frdy are required. The custom essay instructions fwry, frdxlo, and frdxhi are required for context hosting switching (saving and restoring X and Y registers). Just as with single-precision transcendental operations, double-precision transcendental operations will require the option
-funsafe-math-optimizations
There are a few FPGA implementations of the floating-point units described here:
Community support is provided Monday to Friday. Other contact methods are available here.
Intel does not verify all solutions, including but not limited to any file transfers that may appear in this community. Accordingly, Intel disclaims all express and implied warranties, including without limitation, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement, as well as any warranty arising from course of performance, course of dealing, or usage in trade.
For more complete information about compiler optimizations, see our Optimization Notice.