Shop OBEX P1 Docs P2 Docs Learn Events
Mixing C and PASM — Parallax Forums

Mixing C and PASM

Hi,

I know, I know. This must have been asked like a gazillion times but google was not my friend. Or actually I found the questions but not a lot of clear answers.

I have a nice little project where I think Propeller is a good match. I've sketched the functionality I want to implement with cogs in PASM(*) but I don't fancy writing the 'main' program in Spin, I want to write it in C.

I have a couple of .spin files with the PASM code in the DAT section.

But how can I launch in C the PASM code in the .spin files? How do I tie all the parts together? What tool chain should use?

I've so far dabbled with PropellerIDE and SimpleIDE. In SimpleIDE I can write, compile, load and execute C code on a Propeller board. But using Spin/Pasm fails on macOS.

PropellerIDE 'works' with Spin/Pasm but does not allow C.
(Or somewhere it said it allows that but I cannot get that to work on macOS, does not allow opening/saving .c or .h files, in fact it does not even allow creating .spin files but is happy to edit them.)

I'd be most happy with command line compiler/linker and a Makefile, then I could integrate the stuff to real professional IDE like Eclipse or something or use vim,emacs, anything that really does what it says on the tin.

As IDEs all the Propeller IDEs I've used (or tried to use) are sub par. Why is the wheel always re-invented...

Ok, sorry about the rant, that was not the the point, just please somebody point me to documentation on how to mix Pasm and C, I don't need Spin.


(*) Writing PASM is what a Propeller is all about. If what I want to do could be done in Spin then it should be doable in C and if it can be done in C why do it in Propeller when there so many other MCU at better prices, better IO, better suited to C (for some definition of 'better'). IMO writing medium complexity medium speed timing critical/deterministic stuff is where you want to use Propeller. Something where you would use a small FPGA but cannot because you don't have the skills or resources.

Comments

  • Warning: I’m not a C guru. But what you are proposing can be done, is routinely done, and it isnt hard. Take a look at FlexGUI. It supports BASIC, C, PASM and Spin and allows each language to talk to routines written in any other FlexGUI-supported language.

    As an example, my “goto” language for rapid dev on the P1/P2 is BASIC. But when BASIC pulls-up lame, I can inline assembly. Or I can write a set of functions in PASM and call them as a class with one line of code. Same goes for Spin, etc. Its like having a Swiss army knife in software.

    You can get it here: https://github.com/totalspectrum/flexgui Eric Smith is the author and he is as close as this forum: @ersmith
  • A few years ago I asked how to speed up SPI read & writes in C. The following link is the full adventure of me being taught how to take a Spin + PASM program (spiasm.spin) from the PropTool library and calling the PASM from a SimpleIDE C program. There is also a discussion of developing a library of functions, but that's not necessary.

    Here's the link:
    https://forums.parallax.com/discussion/157441/can-spi-in-simple-libraries-be-speeded-up

    Additionally, I also took a Spin+PASM for controlling the 17 segment display on the Propeller Professional Development Board (PPDB) written by @Tonyp12, and converted that to call the PASM from C (SimpleIDE). It is a much shorter discussion (2 posts). The link is here:

    https://forums.parallax.com/discussion/comment/1319703/#Comment_1319703

    Hope this helps.
    Tom
  • Cluso99Cluso99 Posts: 18,069
    Years ago I used Catalina C together with P1 ASM programs that I wrote.
    Ross has numerous examples that come with his download. Not sure if it runs on a Mac (or Unix) tho. He recently revised Catalina as it now does P2 as well. see the Catalina thread (might be under P2)
  • I have written several program and found mixing assembly code in C some what difficult to do. It's not the same as when it's put in a spin program. Documentation is limited.

    In most cases I avoid assembly because C generate as close to assembly as possible and I make sure I set my Memory Model to LMM Main Ram.

    Here is a sample program for you to look at to get the idea of how assembly is done.
    #include <simpletools.h>
    
    unsigned long getData(int);
    
    unsigned long start;
    unsigned long end;
    
    
    int main()
    {
    
      unsigned long i, j;
      unsigned long k, l;
      
      input(15);
      while (1)
      {
      
      i = getData(15);
      j = getData(15);
      if ((i != k) && (j != l))
      {
        print("Value: %x, %x  \n", i, j);
        k = i;
        l = j;
      }
      
      }    
    }
    
    unsigned long getData(int pin)
    {
      int waitcycles;
      int j = 8;
      int cycle1 = 800;
      int bitcycles;
      int rxmask;
      unsigned long value;
      
      rxmask = 1 << pin;
      bitcycles = cycle1;
      cycle1 += cycle1 >> 2;  //move to center of pulse
      waitcycles = cycle1;
      
      /* wait for a start bit */
      waitpne(0, rxmask);
      waitcycles += CNT;
    
      while(j-- > 0)
      {
        // waitcycles = waitcnt2(waitcycles, bitcycles); */
        __asm__ volatile (
        "       waitcnt %[_waitcycles], %[_bitcycles] \n\t"
        "       shr %[_value],#1                      \n\t"
        "       test %[_mask],ina wz                  \n\t"
        "       muxz %[_value],#128                    \n\t"
              : [_waitcycles] "+r" (waitcycles),
                [_value] "+r" (value)
              : [_bitcycles] "r" (bitcycles),
                [_mask] "r" (rxmask));
    
        /* value = ( (0 != (INA & rxmask)) << 7) | (value >> 1); */
      }
      return value; /* fcached 0x40 or 64 bytes */
    }
    
    void doAsm(void *par)
    {
      int rxbits;
      int wcnt;
      int rxdata;
      int Data;
      int rxmask;
      int baud;
      
          __asm__ volatile (
          "     waitpne 0, %[_mask]        \n\t"
          "     mov %[_rxbits], #9         \n\t"
          "     mov %[_wcnt], %[_baud]     \n\t"
          "     shr %[_wcnt], #1           \n\t"
          "     add %[_wcnt], cnt          \n\t"
          "bit: add %[_wcnt], %[_baud]     \n\t"
          "     waitcnt %[_wcnt], %[_baud] \n\t"
          "     test %[_mask], ina  wc     \n\t"
          "     rcl %[_rxdata], #1         \n\t"
          "     djnz %[_rxbits], #bit      \n\t"
          "     mov %[_data], %[_rxdata]   \n\t"
            :[_rxbits] "+r" (rxbits),
             [_wcnt] "+r" (wcnt),
             [_rxdata] "+r" (rxdata),
             [_data] "+r" (Data)
            :[_mask] "r" (rxmask),
             [_baud] "r" (baud)
          );
    }
    

    Also if you look at the Help menu item and pick PropGCC reference you can get to the documentation on in line assemble shown here Inline Assembly

    Also I have not been able to build a pure assembly cog. There must be some C code and then you can put the inline assembly.

    In most cases I was able to use C macros that use assembly code to get around using assembly when possible.

    Hope this helps.

    Mike
  • yetiyeti Posts: 818
    edited 2020-01-27 13:28
    I'd start with FastSpin and HomeSpun and/or OpenSpin these days to get the best of all worlds (bytecode Spin and LMM/COG Spin/PASM/BASIC/C).

    If you want mainly PASM, have a look at naken_asm and its Propeller examples.
  • Hi thanks everyone.

    I think I have managed to do what I want.

    I've settled on SimpleIDE which seems to work once I understood some of the <epithet suppressed> user interface.

    I can write the main program in C and launch pasm code to run on the cogs and write the cog code as pasm in .spin files.

    Pretty simple but the details were difficult to find among all the noise in the internet.

    Not run any code yet but it all compiles.
Sign In or Register to comment.