G8JCF
Guru
Joined: 15/05/2014 Location: United KingdomPosts: 676 |
Posted: 01:05pm 31 Oct 2014 |
Copy link to clipboard |
Print this post |
|
In the course of developing a CFunction, @Plasma discovered an issue with the way multiple inline assembler NOP statements are handled by the MPLabX disassembler and CFuncGen. I have updated the MMBasic CFunctions tutorial which will be republished soon, but in the meantime here is the relevant section reproduced below.
Assembler NOPs
It is very common to use NOPs in timing/delay loops. XC32/gcc is very good at spotting 'useless' NOPs and will often eliminate them completely from the emitted machine code. In addition, there is a problem when several NOPs in sequence are inserted inline into the 'C' code, although xc32/gcc/xc32-as emits the correct machine code, the disassembly output which is used by CFuncGen omits these NOPs. Quite why is a complete mystery.
To get round this problem, an alternative to NOP which does not suffer from these problems must be used. After some trial and error, a good alternative to NOP is ori $0,$0,0 or li $0,0 instruction, which is load Register 0 with value 0, Register 0 is MIPS register which always contains zero . See an example usage below
asm volatile ("ori $0,$0,0\n\t"
"ori $0,$0,0\n\t"
"ori $0,$0,0\n\t"
"ori $0,$0,0\n\t"
"ori $0,$0,0\n\t"
);
[/CODE}
And the disassembly output in CFuncGen is
[CODE}
9d0000fc: 34000000 li zero,0x0
9d000100: 34000000 li zero,0x0
9d000104: 34000000 li zero,0x0
9d000108: 34000000 li zero,0x0
9d00010c: 34000000 li zero,0x0
The volatile prefix should prevent the optimizer from eliminating this code.
So in sum instead of writing nop, write li $0,0; use a #define to make it easier, eg #define NOP li $0,0
This code seems to work. Any feedback/suggestions for improvement would be most welcome.
Peter
The only Konstant is Change |
twofingers Guru
Joined: 02/06/2014 Location: GermanyPosts: 1139 |
Posted: 07:13am 01 Nov 2014 |
Copy link to clipboard |
Print this post |
|
Hi Peter,
I'm not coding CFunctions yet, but I would expect NOP are much faster than that "li $0,0". I think you can more fine tune do with NOPs.I don't know if that will be a problen in the future. Just a idea.
But you did of course a amazing good job, because you care about CFunctions (and how to handle) and the whole rest of computers! ;)
For me your tools and your manual are the key to use CFunctions and to become popular! (seriously!)
Thanks a lot!
Michael |
G8JCF
Guru
Joined: 15/05/2014 Location: United KingdomPosts: 676 |
Posted: 11:49am 01 Nov 2014 |
Copy link to clipboard |
Print this post |
|
In MIPS/RISC processors, just about every one of the simple instructions take one cycle - conditiional/branch/jump instructions are a bit more complicated timing wise. NOP in MIPS, is in fact SLL $0,$0,0, ie there is not actually a NOP instruction in MIPS.
For delay loops, people should be using Geoff's CFunction Delay
// delay for a certain number of core timer ticks
//(one tick every 50nS at 40MHz CPU speed, 100nS at 20MHz, etc)
void Delay(unsigned int ticks) {
unsigned int current_ticks = 0;
// set the core timer to zero
asm volatile("mtc0 %0, $9": "+r"(current_ticks));
do {
// get the core timer ticks
asm volatile("mfc0 %0, $9" : "=r"(current_ticks));
} while(current_ticks < ticks);
}
'C:\CFunctions\Tutorial_4_CFunctionLib.X\dist\default\produc tion\Delay.bas
'
'Delay 2014-10-20 22:40:46 CFuncGen Ver 1.0.16 by user=Peter
'
CFunction Delay
00000000
00001021 40824800 40024800 0044102b 1440fffd 00000000 03e00008 00000000
End CFunction
which generates accurate and precise delays. Do/While with NOPs is what we all used to use pre PIC32, but Geoff's function is much, much better.
Thanks Michael for the encouraging comments.
Peter The only Konstant is Change |