Inline asm not working as expected
danielstritt
Posts: 43
Ok, I am learning PASM as inline assembly in my C programs. This is a copy of entire program as it doesn't flash quickstart leds every second:
Now, if I uncomment "pause(1000)" it runs just fine on my quickstart. If I leave it commented it does not flash the lights as expected. I understand that a brief pause is required before using statements such as "printf", but is it also needed before ASM statements? I'm confused
Thanks
Daniel
#include <propeller.h> #include "simpletools.h" int main(void) { //pause(1000); __asm__ volatile ( "mov r1, #0xff\n\t" "shl r1, #16\n\t" "or dira, r1\n\t" "or outa, r1\n\t" "my_label: " "rdlong r2, #0\n\t" "add r2, cnt\n\t" "or outa, r1\n\t" "rdlong r2, #0\n\t" "add r2, cnt\n\t" "waitcnt r2, #0\n\t" "andn outa, r1\n\t" "rdlong r2, #0\n\t" "add r2, cnt\n\t" "waitcnt r2, #0\n\t" "brs #my_label\n\t" ); return 0; }
Now, if I uncomment "pause(1000)" it runs just fine on my quickstart. If I leave it commented it does not flash the lights as expected. I understand that a brief pause is required before using statements such as "printf", but is it also needed before ASM statements? I'm confused
Thanks
Daniel
Comments
If you need that kind of control, you should launch assembly in a COG.
It might be getting put into fcache, and that might break your code. If it is you'll be able to see that happening in the assembly output.
Here is some code that intentionally goes into the fcache:
I disagree a bit on that point. My example case? An I2C driver, where all realtime happenings work at the command of the master. Most of the Propeller objects have an unfortunate flaw: you must use two cogs to do one thing. One cog for the realtime, and one cog for the processing. With PropellerGCC, in certain circumstances, you can merge these functions into a single cog. I2C is a good example: you want the speed and precision, but you don't need it all the time. In between you want the ease of programming that C offers. The above function shows a bit of that. Anyway, that's my opinion.
Doing a JMP to __LMM_RET is different because it is a predefined symbol for the function return address in LMM mode.
I use in-line ASM in the 115200 bps simple serial driver in libsimpletext and other drivers for one-COG solutions. Such things are very valuable. I wouldn't use any tricks in this kind of code though.
In case it matters, optimizer was off, and memory model was LMM.
I guess my problem was solved, I will just have to read more docs on PropGCC to understand the options better.
Thanks
Daniel
It sounds like the original problem was the "Enable pruning" option. My guess is that without the pause() call, the compiler thought nothing was happening in main and removed the whole program.
Shouldn't the __volatile__ in "__asm__ __volatile__" prevent the inline assembly sequence from getting pruned?
===Jac
That will protect it from the compiler, but perhaps not the linker. That's the only explanation I can think of for his described behavior. I think turning off linker pruning is the easiest work-around.
As far as I understand, the linker works at the function level, and uses references to determine which functions are needed; unreferenced functions (functions that aren't called by any other function) are pruned. The main function should never get pruned by the linker because it gets called by the C runtime startup code which is at the entry point into the executable file. In other words, I'm still not sure if pruning is the reason that the code doesn't work.
Maybe danielstritt can post the assembly output of the failing code?
===Jac
No pruning, works as expected:
With pruning, lights on quickstart don't turn on or blink (not really sure what it's doing then):
I hope this helps.
Daniel
Are you running this as a program saved to the EEPROM ?
We had some trouble with pruning and EEPROM that was fixed in version release_1_0_2097. I have a new build, but we are still testing with it.
Thanks
Daniel
I'll post a pointer to the latest package after more testing.
Thanks
Daniel