Forum Discussion
NIOS2 HW & DIV Instructions + FPU
Hello i am in charge of designing a system that does a lot of complex sin/cos/* instructions and i need them to be fast.
I am using NIOS2-F at 100mhz in a Cyclone IV. I've enabled HW and DIV by hardware at NIOS2-F and i am using 64K data and instruction cache. My software is being compiled with these flagsCFLAGS = -Wall -DNOCRYPT -mhw-div -mhw-mul -mcustom-fpu-cfg=60-1 -mcustom-fpu-cfg=60-2 -O3
I tried to use the Custom FPU instruction at QSys but my performace is slower with Custom FPU instruction attached to NIOS2-F at QSYS (why?) Is there anything else i can do? Any suggestions?28 Replies
- Altera_Forum
Honored Contributor
Depending on what you are doing you might be able to reduce the amount of maths required!
If you only need limited precision use a lookup table and linear interpolation (and maybe a single newton-raphson step). If you are generating values in sequence (eg tone generation) then use the equality: sin(a+b) = 2sin(a)cos(b) - sin(a-b) Use fixed-point maths (in integers) rather than floating point. - Altera_Forum
Honored Contributor
Thanks for your help but i can't do this math optimizations :S
Maybe if i change the GCC i can get a better result? I am using version 3.4.6 - Altera_Forum
Honored Contributor
Changing the version of gcc won't make much difference.
It might be worth looking at the generated code (either pass '-S -fverbose_asm' to gcc and look at the generated .s file, or run 'objdump -d' on the object/program file). Also remember that (IIRC) the FP opcodes only do 'float' not 'double', and you don't want to be converting between float and double either. - Altera_Forum
Honored Contributor
I will take a look into that, DSL why i get a worse performance when i add the float point unit custom instruction at NIOS2 @ QSys?
Doesnt make sense to me, NIOS2 already have those custom instructions built in? Also what should i be looking for in the objdump? (Never used this command:eek:) This is a part of my meter_run (main function)
I Guess it is using custom instructions right? (Even thought i didnt add the custom instruction guy @ QSys)4e0c: 39000017 ldw r4,0(r7) 4e10: 31800104 addi r6,r6,4 4e14: 10c7ff32 custom 252,r3,r2,r3 4e18: 1105ff32 custom 252,r2,r2,r4 4e1c: 40d1ff72 custom 253,r8,r8,r3 4e20: 4893ffb2 custom 254,r9,r9,r2 4e24: 39c00104 addi r7,r7,4 4e28: 29400904 addi r5,r5,36 4e2c: 32bff51e bne r6,r10,4e04 <meter_run+0xb4> 4e30: 73800044 addi r14,r14,1 4e34: 5a400015 stw r9,0(r11) 4e38: 62000015 stw r8,0(r12) 4e3c: 6b400104 addi r13,r13,4 4e40: 63000104 addi r12,r12,4 4e44: 5ac00104 addi r11,r11,4 4e48: 73ffe31e bne r14,r15,4dd8 <meter_run+0x88> 4e4c: d8c00217 ldw r3,8(sp) 4e50: d1e09117 ldw r7,-32188(gp) 4e54: d2e09017 ldw r11,-32192(gp) 4e58: d9000617 ldw r4,24(sp) 4e5c: da400117 ldw r9,4(sp) 4e60: da800517 ldw r10,20(sp) 4e64: d9400317 ldw r5,12(sp) 4e68: d2209317 ldw r8,-32180(gp) 4e6c: d3209217 ldw r12,-32184(gp) 4e70: 1ac5ff32 custom 252,r2,r3,r11 4e74: d9800717 ldw r6,28(sp) 4e78: 19c7ff32 custom 252,r3,r3,r7 4e7c: 1a47ff72 custom 253,r3,r3,r9 4e80: 390fff32 custom 252,r7,r7,r4 4e84: 1285ff72 custom 253,r2,r2,r10 4e88: 22c9ff32 custom 252,r4,r4,r11 4e8c: 1907ffb2 custom 254,r3,r3,r4 4e90: 11c5ff72 custom 253,r2,r2,r7 4e94: 2b09ff32 custom 252,r4,r5,r12 4e98: 2a0bff32 custom 252,r5,r5,r8 4e9c: 1947ff72 custom 253,r3,r3,r5 4ea0: 1105ff72 custom 253,r2,r2,r4 4ea4: 4191ff32 custom 252,r8,r8,r6 4ea8: 330dff32 custom 252,r6,r6,r12 4eac: 19a9ffb2 custom 254,r20,r3,r6 4eb0: 1227ff72 custom 253,r19,r2,r8 - Altera_Forum
Honored Contributor
The sine/cosine implementations of the IEEE variant of newlib use lookup tables to compute the result so I wouldn't expect adding the FPU to make any difference at all. If you want a faster implementation you either need to look for software optimizations or implement the sine/cosine in hardware and bolt it up to the CPU as a custom instruction. There are compiler flags you can pass in to tell the tools to use the custom instruction implementation instead of the software library.
Optimizations you can look at are taylor series, cordic, etc..... Some may work well in software with the FPU and some would make more sense being offloaded into hardware. There are others you can look at if you want to trade off accuracy or have inputs that are bound to the point where you can use lookup tables efficiently. If you are seeing those 'custom' opcodes without a custom instruction then I would think you are having the wrong code linked in. It could be that code is being linked in but never executed but that would surprise me. - Altera_Forum
Honored Contributor
--- Quote Start --- If you are seeing those 'custom' opcodes without a custom instruction then I would think you are having the wrong code linked in. It could be that code is being linked in but never executed but that would surprise me. --- Quote End --- Yes that IS really weird because i am not using the custom instruction IP at QSys. However if i dont use the compiler flags my code runs 70~80% slower. - Altera_Forum
Honored Contributor
Well if those instructions are called with no implementation then it'll probably result in one cycle per instruction but the results would be incorrect. Also you are not adding those flags manually are you? In your earlier post I see two usages of "mcustom-fpu-cfg" which shouldn't be happening since you are either using 60-1 (+, -, *) or 60-2 (+, -, *, /) and I'm not sure what happens when both are specified. This flag should have been passed in automatically for you.
- Altera_Forum
Honored Contributor
I'm not sure which functions are in 'newlib' (libc), but for speed you'd want the sin/cos functions that act on float (not double) and have compiled newlib itself to use the FP custom instructions.
- Altera_Forum
Honored Contributor
--- Quote Start --- Well if those instructions are called with no implementation then it'll probably result in one cycle per instruction but the results would be incorrect. Also you are not adding those flags manually are you? In your earlier post I see two usages of "mcustom-fpu-cfg" which shouldn't be happening since you are either using 60-1 (+, -, *) or 60-2 (+, -, *, /) and I'm not sure what happens when both are specified. This flag should have been passed in automatically for you. --- Quote End --- Humm when both are specified the last one is valid i guess, and yes i am adding those flags manually, what other way can i do it? I am compiling my aplication from Linux --- Quote Start --- I'm not sure which functions are in 'newlib' (libc), but for speed you'd want the sin/cos functions that act on float (not double) and have compiled newlib itself to use the FP custom instructions. --- Quote End --- How can i do this? - Altera_Forum
Honored Contributor
Hmmm..... I've just been looking at the newlib sources (from the gcc 3 build).
There seem to be 2 copies of the trig functions, both seem to use the taylor series (possibly with lightly modified coeffs to reduce the error). I'm not sure how well either version will actually compile for nios2, for speed you probably want the constants loaded from the 'small data' segment - and I don't think that will happen with the given code and the altera built compiler. I'd also check that GET_FLOAT_WORD() doesn't involve a memory write-read - if so replace with an inline asm function. You might find it worth while getting those sources and compiling the functions as part of your app - that will make changing them much easier.