Shop OBEX P1 Docs P2 Docs Learn Events
Spin2Cpp (or maybe PropGCC) questions — Parallax Forums

Spin2Cpp (or maybe PropGCC) questions

RaymanRayman Posts: 14,665
edited 2013-03-29 10:07 in Propeller 1
First, let me say that Spin2Cpp is amazing and wonderful.

But, of course, I have to look the gift horse in the mouth a bit...

I'm trying to clean up the code to look more like something I would have wrote myself...
But, there are a few things I don't understand in there...

First, can you remind me why we are using "int32_t" and not just "int".
I was looking at the GNU C Reference manual data types and "int" looks right...
http://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Primitive-Types
Both P1 and P2 are 32-bit, so why create our own type here?
The hello.c example uses just "int"
The fft_bench.c example does this:
#define int32_t int#define int16_t short int
Again, this only makes sense to me if we thought we might want to define int32_t to be something else, which I don't see happening...

Next question is about Yield.
My simple SPIN "repeat" was turned into a loop containing "Yield()".
Having a yield function would make sense if we were doing some kind of multitasking...
Do I really need that there if I just want the program to spin it's wheels indefinitely?
The top of the code has this:
#ifdef __GNUC__
#define Yield__() __asm__ volatile( "" ::: "memory" )
#else
#define Yield__()
I'm very unclear on this part... When is __GNUC__ defined?
What in the world does that first define do?
Does the second define just mean that Yield is replaced by nothing?

Lastly (for now), what is this all about?:
#ifdef __GNUC__
#define PostEffect__(X, Y) __extension__({ int32_t tmp__ = (X); (X) = (Y); tmp__; })
#else
#define PostEffect__(X, Y) (tmp__ = (X), (X) = (Y), tmp__)
Code seems to work with this commented out... When is it needed?

Actually, do have one more question (sorry):
I can build and run the output using either "propeller-elf-c++" or "propeller-elf-gcc".
My understanding is that the first one is for C++ code and the second one for C code.
Spin2Cpp implied to me that the output was C++ code. But, I think I remember that this is only when you have assembly drivers included.
Is that right? Can SPIN only code sent through Spin2Cpp always be used both ways?

Comments

  • ersmithersmith Posts: 6,054
    edited 2013-03-29 07:25
    Rayman wrote: »
    First, let me say that Spin2Cpp is amazing and wonderful.
    Thanks!
    First, can you remind me why we are using "int32_t" and not just "int".
    "int32_t" is the C99 standard way of specifying a 32 bit integer (see the header file <stdint.h>). It will work on any platform, and will work on future 64 bit Propellers. As it happens "int" is 32 bits on PropGCC, but not on the 64 bit Linux where I've been doing my development.
    My simple SPIN "repeat" was turned into a loop containing "Yield()".
    Empty repeat loops are often used to wait for hardware or another COG to do something. The GCC optimizer can be pretty aggressive about moving and deleting code, so I put the call to Yield() in to prevent it from moving anything past the loop. The __asm__ volatile with "memory" as a clobber indicates that any memory might change during the loop, and again is to keep the optimizer from making assumptions. It won't actually add any code, it's just a note to the compiler that the outside world may be doing things that we don't know about. In pure C code you'd normally mark variables as "volatile" for this, but spin2cpp isn't able to do enough analysis to tell which variables might be variable.
    When is __GNUC__ defined?
    It's always defined by the GNU C compiler, and expands to the GCC version number. Most compilers have those kinds of defines, so you can write code that can take advantage of compiler specific features. I think Visual C defines __MSV_VER for a similar purpose. PropGCC defines a bunch of things (see the manual for a list of all of them); some of the interesting Propeller specific ones are:
    __PROPELLER__      is always defined by PropGCC, to note that we're compiling for the propeller)
    __PROPELLER_LMM__  is defined in LMM mode
    __PROPELLER_CMM__  is defined in CMM mode
    __PROPELLER_XMM__  is defined in XMM mode
    __PROPELLER_XMMC__ is defined in XMMC mode
    __PROPELLER_USE_XMM__ is defined in either XMM or XMMC modes
    __PROPELLER_64BIT_DOUBLES__ is defined when doubles are 64 bits long
    __PROPELLER_32BIT_DOUBLES__ is defined when doubles are 32 bits long
    __PROPELLER2__      is defined when compiling for P2
    
    Lastly (for now), what is this all about?:
    #ifdef __GNUC__
    #define PostEffect__(X, Y) __extension__({ int32_t tmp__ = (X); (X) = (Y); tmp__; })
    #else
    #define PostEffect__(X, Y) (tmp__ = (X), (X) = (Y), tmp__)
    
    Code seems to work with this commented out... When is it needed?
    It's used for compiling some Spin expressions that modify a variable but return the original value (like "X^^"). If you don't use those expressions, it won't be needed.
    I can build and run the output using either "propeller-elf-c++" or "propeller-elf-gcc".
    My understanding is that the first one is for C++ code and the second one for C code.
    propeller-elf-gcc and propeller-elf-g++ both can compile C or C++ code (they use the file extension to tell which is which). The difference comes in the final link step: g++ includes the standard C++ libraries, and gcc does not. For spin2cpp generated code, which does not use any C++ libraries, it doesn't matter.

    Eric
  • RaymanRayman Posts: 14,665
    edited 2013-03-29 07:52
    Thanks. I think I see that you used "int32_t" so you can run the code on your 64-bit Linux setup for testing.
    For me, this is not a problem because Windows can run 32-bit code with 64-bit OS just fine.
    So, I think maybe I'll be able to build and run with Visual Studio using plain "int".
    Also, I think it will be a very, very long time until there's a 64-bit Propeller...

    I'm not sure what I'll do about the yield. Think I'll try just deleting it and see if the optimizer punishes me...

    I'm not clear on the posteffect part. Doesn't C++ handle things like "x++" the same way as Spin?
    I do have a "dira[11]~~ " in there, which is post-set, but it just get's turned into:
    DIRA = ((DIRA & 0xfffff7ff) | 0x800);

    so, I guess I'll have to try "X^^" and see what that gets turned into.
  • TorTor Posts: 2,010
    edited 2013-03-29 09:21
    ersmith wrote: »

    "int32_t" is the C99 standard way of specifying a 32 bit integer (see the header file <stdint.h>). It will work on any platform, and will work on future 64 bit Propellers. As it happens "int" is 32 bits on PropGCC, but not on the 64 bit Linux where I've been doing my development.
    This is incorrect. 'int' is 32 bits on your 64-bit Linux platform, and it is 32 bits on every reasonably modern Unix-like platform. It's 32 bits on IRIX (32- and 64-bit variants), AIX (likewise), Tru64 (which is a pure 64-bit Unix), Solaris (32- and 64-bit variants), and Linux (32- and 64-bit variants). It's all part of a standard negotiated between vendors more than 20 years ago (I have the whitepaper somewhere).

    What's different between 32- and 64-bit platforms is the size of 'long', which is defined to be the size of a pointer: 4 bytes on 32-bit platforms, 8 bytes on 64-bit platforms (the notable exception here is Windows 64, which makes it a troublesome platform). 'long long' is, under the same agreement, defined to be 64 bits on 32- as well as 64-bit platforms.

    Maybe you were thinking about 'long'?


    -Tor
  • ersmithersmith Posts: 6,054
    edited 2013-03-29 10:04
    Rayman wrote: »
    Thanks. I think I see that you used "int32_t" so you can run the code on your 64-bit Linux setup for testing.
    Well, and also for clarity -- the Spin LONG type is exactly 32 bits, but the C "int" type is not necessarily any specific number of bits. Personally I'd recommend avoiding "int", But if you're using Visual Studio you'll have to find a 3rd party <stdint.h>, Microsoft has been steadfastly refusing to update their C to the current standard (which is 14 years old now, for goodness sake!).
    I'm not sure what I'll do about the yield. Think I'll try just deleting it and see if the optimizer punishes me...
    Why not leave it in? It won't hurt anything.
    I'm not clear on the posteffect part. Doesn't C++ handle things like "x++" the same way as Spin?
    For things that they both have, yes. But as you've pointed out, there are operators like "~~" that Spin has but C++ doesn't. For example,
      x := y~~ + 1
    
    is translated by spin2cpp into something like:
      X = (PostEffect__(Y, -1)) + 1;
    
    Which sets X to Y+1 and then Y to -1.

    If the postfix result is never used (like in your DIRA example) spin2cpp optimizes it away. So you only need the PostEffect__() define if it actually occurs in your source code. The spin2cpp macro generation code isn't quite smart enough to eliminate that, although I probably should fix that.

    (And forget my earlier ^^ example, it isn't valid.)

    Eric
  • ersmithersmith Posts: 6,054
    edited 2013-03-29 10:07
    Tor wrote: »
    This is incorrect. 'int' is 32 bits on your 64-bit Linux platform, and it is 32 bits on every reasonably modern Unix-like platform.
    You're right, I was thinking of "long", and also of the fact that Spin uses LONG both for integers and pointers, which are not the same size on all platforms.
    I was also thinking of other compilers I've used where "int" is certainly not 32 bits (e.g. many microcontrollers).

    I think it's a good habit to get into using <stdint.h> whenever a specific size is required, and Spin does expect 32 bit integers.

    Thanks,
    Eric
Sign In or Register to comment.