Shop OBEX P1 Docs P2 Docs Learn Events
PropGCC / PASM question — Parallax Forums

PropGCC / PASM question

I have a bunch of code that I've written in Spin / PASM. Most of the code is PASM, but the high-level code is Spin, and I'm thinking that C might be a better choice, because it'll get the benefit of the optimizer and likely gain some speed.

My question: Is it possible to compile a GCC project with my pre-existing PASM functions running in COG mode (not CMM or LMM) but still be able to choose the CMM model for the high-level code?

Are there examples around for setting up something like this? The PropGCC and Learn pages have very little info on using PASM, other than inlining, and that implies that it's being assembled into the same global code model.
«13456

Comments

  • I believe the version of Full Duplex Serial that comes with PropGCC does something like this. I copied that method to make the PASM quadrature encoder object useable from C.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2015-10-13 03:16
    Can you use SimpleIDE to build things like that, or did you need to use a makefile? (and thank you, I'm looking at that code now, and it looks like exactly what I wanted)
  • I use mixtures of PASM cog code and high-level hub code (which can be either LMM or CMM but not both) by putting the PASM into *.S files, one per driver cog.

    While propgcc gas will compile PASM straight from the DAT section of a SPIN file, the extensions available with gcc (macros & conditional compilation, e.g.) are compelling and it's hard to switch back.

    I'm pretty sure you can do this with SimpleIDE, but I use Makefiles, which allows me to automate compiling the cog drivers as ECOGs, which loads them directly from the upper 32K of a 64K+ EEPROM, freeing up hub space for more CMM or LMM code.

    It is all explained in different places, but I haven't seen a single resource that steps you through it. I've promised more than once to write up a tutorial on how to do this, but it has never gotten done.

  • I have the code getting through the compiler (first stage), but then when processing the output in the cmm folder it dies.

    I've attached a simple test project if anyone's feeling ambitious. The RC_Receiver.sx file gets through the assembler with no issues, and the RC_Receiver.c file compiles fine.

    Then I get a bunch of these:
    cmm/RC_Receiver.sx:1:8: warning: null character(s) ignored [enabled by default]
    cmm/RC_Receiver.sx:12: Error: Unknown instruction 't X X \ '

    ...and the build fails.

    Any help from the PropC gurus who've done this already would be much appreciated.

    Jason
  • SRLMSRLM Posts: 5,045
    You can check out some existing code. Both David and I have done some C++&GAS programming. Here's a serial driver in libpropeller:

    https://github.com/libpropeller/libpropeller/tree/master/libpropeller/serial

    And here's propware: https://github.com/DavidZemon/PropWare
  • lately I've been steering away from COGC modules in favor of inline assembly, and converting my old examples while I'm at it, so my pool is dwindling. But, I still have one simple example that works with PropWare's build system:
    https://github.com/DavidZemon/PropWare/tree/release-2.0/Examples/Cogc

    Jason, I'm downloading your project now...
  • lately I've been steering away from COGC modules in favor of inline assembly, and converting my old examples while I'm at it, so my pool is dwindling. But, I still have one simple example that works with PropWare's build system:
    https://github.com/DavidZemon/PropWare/tree/release-2.0/Examples/Cogc

    Jason, I'm downloading your project now...
    Is there a reason you're steering away from COGC modules? I would think they would give you better performance than inline LMM assembly. Do you not need the higher performance?

  • First thing: I've never heard of the .sx extension... some googling lead me to freescale. Are you sure that's normal or are you jumping out of the freescale world and thinking that sx is a generally assembly language extension? The ones I'm familiar with are s and S (where S implies preprocessor-macro exist in the file).

    Second, I strongly dislike assembly files in PropGCC. They cause no end of pain and grief. I had a lot of trouble getting my SPI module to work, because it was written in an assembly file. I haven't seen those preprocessor macros in propeller.h before though - that's pretty neat.
  • I think ".sx" is the same as ".S" for operating systems that don't distinguish case. They both cause the preprocessor to be run on the source file before it is fed to the assembler.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2015-10-13 13:38
    The PropGCC project contains both, so I tried both. Using .s it wouldn't assemble my file and choked on the first PASM opcode, whereas .sx assembled fine and died later. I'm just taking blind potshots here.

    I'm on Windows, and using SimpleIDE. I haven't used command line tools and makefile a for PropGCC before and was hoping I wouldn't have to.
  • Lowercase .s will not run the preprocessor so you will get errors if your code includes preprocessor statements.
  • Here is what the GCC documentation says:

    file.s
    Assembler code.

    file.S
    file.sx
    Assembler code that must be preprocessed.

    However, it looks like you might need to use gcc for this to work. I don't think running propeller-elf-as by itself will honor these rules.
  • No preprocessor statements that I recall - I think the file is straight PASM. I'm starting to suspect SimpleIDE may not be differentiating them properly, or I need a different version of PropGCC. I'll have to see if I can figure out what I've got.
  • Here is what happened when I tried to assemble your .sx file. It looks like it worked to me.
    david-betzs-macbook-pro:Main dbetz$ propeller-elf-gcc -c -o RC_Receiver.o RC_Receiver.sx
    david-betzs-macbook-pro:Main dbetz$ propeller-elf-objdump -t RC_Receiver.o
    
    RC_Receiver.o:     file format elf32-propeller
    
    SYMBOL TABLE:
    00000000 l    d  .text	00000000 .text
    00000000 l    d  .data	00000000 .data
    00000000 l    d  .bss	00000000 .bss
    00000000 l    d  .rc_receiver_cog	00000000 .rc_receiver_cog
    00000000 l       .rc_receiver_cog	00000000 entry
    00000000 l       .rc_receiver_cog	00000000 rc_INIT
    00000114 l       .rc_receiver_cog	00000000 p1
    000000fc l       .rc_receiver_cog	00000000 pin_mask
    00000010 l       .rc_receiver_cog	00000000 _loop
    00000108 l       .rc_receiver_cog	00000000 d2
    00000104 l       .rc_receiver_cog	00000000 d1
    00000100 l       .rc_receiver_cog	00000000 c1
    0000010c l       .rc_receiver_cog	00000000 d3
    00000030 l       .rc_receiver_cog	00000000 _POS
    00000074 l       .rc_receiver_cog	00000000 _NEG
    00000138 l       .rc_receiver_cog	00000000 pin_mask_0
    00000118 l       .rc_receiver_cog	00000000 pe0
    0000013c l       .rc_receiver_cog	00000000 pin_mask_1
    0000011c l       .rc_receiver_cog	00000000 pe1
    00000140 l       .rc_receiver_cog	00000000 pin_mask_2
    00000120 l       .rc_receiver_cog	00000000 pe2
    00000144 l       .rc_receiver_cog	00000000 pin_mask_3
    00000124 l       .rc_receiver_cog	00000000 pe3
    00000148 l       .rc_receiver_cog	00000000 pin_mask_4
    00000128 l       .rc_receiver_cog	00000000 pe4
    0000014c l       .rc_receiver_cog	00000000 pin_mask_5
    0000012c l       .rc_receiver_cog	00000000 pe5
    00000150 l       .rc_receiver_cog	00000000 pin_mask_6
    00000130 l       .rc_receiver_cog	00000000 pe6
    00000154 l       .rc_receiver_cog	00000000 pin_mask_7
    00000134 l       .rc_receiver_cog	00000000 pe7
    00000110 l       .rc_receiver_cog	00000000 d4
    
  • I strongly dislike assembly files in PropGCC. They cause no end of pain and grief. I had a lot of trouble getting my SPI module to work, because it was written in an assembly file..

    David, this the first I've heard this from you, and I must say I'm a little shocked. Are you *sure* that the problem you were having was *because* it was written in an assembly file ?

    With inline assembly, you lose a lot of the preprocessor goodies, and it's hard to edit and visually unappealing, to say the least. I've had nothing but good experiences from using *.S files; it allows much better automation and control than inline assembly or PASM within a SPIN file.

    If you have the time, could you summarize or publish what you were having a problem with ? I'd hate for new users that are debating whether to use it to run across this and shy away because of it; it works so well for me that it's the only way I do or will program the prop.

    David

    (Yes, there might be too many Davids in this thread; "altosack" is fine.)
  • My real pain is with drivers - assembly and COGC modules both fall in that category. Assembly files are slightly more problematic though.

    I had just woken up when I wrote that reply this morning. I will edit it when I get home to be more factual and less ranty :)
  • David
    David Betz wrote: »
    Here is what happened when I tried to assemble your .sx file. It looks like it worked to me.

    I suspect it's an issue with SimpleIDE. I have two files, both called "RC_Receiver" but with different extensions. The .c file compiles to cmm/RC_Receiver.o, and the .sx file compiles to cmm/RC_Receiver.sx. It looks like that output should *also* be a .o file, but then the files would collide. If PropGCC uses the extension to decide what to do with the file, it'd mean that it's trying to compile the already processed object output again. I'll try to spend some time on it tonight.

    I was hoping that SimpleIDE would handle this more cleanly for a few reasons:

    1) I'd love to be able to port a few projects from Spin/PASM to C/C++/PASM easily, because I think faster in C/C++ than in Spin.
    2) This specific project is being written with an educational market in mind, so "ease of setup" is high on my list of goals. Having to install a command-line toolchain and learn it, in addition to learning the code, is extra overhead.
    3) I suspect general adoption of PropGCC would be higher if using it was no more effort than using the Prop tool.

    Thanks for all the help - I appreciate it. I really want to see how this project compares in size and speed between the Spin/PASM version and a CMM/PASM version.
  • I would suggest that you not have two files with the same names and different extensions. GCC and GAS will normally want to create .o files no matter what the source file extension is and one .o file could overwrite the other or maybe not even get generated at all.
  • Side question - Is SimpleIDE development continuing? I was under the impression that it was open source, but I can't find it now that Google Code is offline.. Was toying with the idea of poking around in there.
  • JasonDorie wrote: »
    Side question - Is SimpleIDE development continuing? I was under the impression that it was open source, but I can't find it now that Google Code is offline.. Was toying with the idea of poking around in there.
    Yes, it is open source. I'm not sure where jazzed has it located now that Google Code is gone. I'll check with him and let you know.

  • I'm now compiling this on the command line, and getting this error when linking:

    cmm/RC_Receiver.o: In function `_RC_Receiver_Start':
    (.text+0x10): undefined reference to `_binary_RC_Receiver_dat_start'
    collect2: ld returned 1 exit status

    The RC_Receiver_Start() function looks like this:
    void RC_Receiver_Start(void)
    {
      use_cog_driver(RC_Receiver);
      load_cog_driver(RC_Receiver , &RC_Pins[0]);
    }
    

    How do I label the entry point in the PASM code and the load_cog_driver() call so the linkage works?
  • Ummm.... That funky symbol (_binary_RC_Receiver_dat_start) is generated by propeller-elf-objcopy when it converts a binary COG image into a linkable object file.

  • I've found I can just manually add that label in the PASM code, but it's generated as a local, not a global. How would I make it global? (or am I going about this all wrong?)
  • JasonDorie wrote: »
    I'm now compiling this on the command line, and getting this error when linking:

    cmm/RC_Receiver.o: In function `_RC_Receiver_Start':
    (.text+0x10): undefined reference to `_binary_RC_Receiver_dat_start'
    collect2: ld returned 1 exit status

    The RC_Receiver_Start() function looks like this:
    void RC_Receiver_Start(void)
    {
      use_cog_driver(RC_Receiver);
      load_cog_driver(RC_Receiver , &RC_Pins[0]);
    }
    

    How do I label the entry point in the PASM code and the load_cog_driver() call so the linkage works?

    This is the issue I was going detail out when I got home. See my workaround in spi_as.S from PropWare (note that the link is to a specific commit, because I have recently deleted that file and it is no longer available in the default branch)
  • David Betz wrote: »
    Ummm.... That funky symbol (_binary_RC_Receiver_dat_start) is generated by propeller-elf-objcopy when it converts a binary COG image into a linkable object file.

    So do I have to run propeller-elf-objcopy on the output of the assembler before I can link it?
  • Not necessarily. Eric had a way to link drivers into a main program that preserved the driver symbols. I'm afraid I don't remember how he handled that. Maybe he's reading and will comment. I used a three step process to create drivers from C code. First, I compiled the code using -mcog, then I used propeller-elf-objcopy to extract the .text section into a .dat file, then I used objcopy again to create a .cog (really just a .o file) containing those strange symbol names (_binary_drivername_dat_start, _binary_drivername_dat_end, _binary_drivername_dat_size). Only the first is needed to load an image from hub memory but I also needed the _size symbol for drivers I loaded from EEPROM.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2015-10-13 22:23
    SwimDude's method compiled and linked - I can't test it until I get home. So far this is workable, but pretty ugly. Looking through the PropGCC code I saw use_cog_driver / load_cog_driver macros, and assumed that was how it worked.

    Does the load_cog_driver() macro basically resolve to the same thing as this? :
                            .text
                            .global _RC_Receiver_Driver_Start
    _RC_Receiver_Driver_Start
                            mviw r7, #__load_start_RC_Receiver_cog  '' linker magic for the start of the RC_Receiver.cog section
                            shl r7, #2
                            or r7, #8                          '' 8 means first available cog
                            shl r0, #16                        '' assumes bottom two bits of r0 are 0, i.e. arg must be long aligned
                            or r0, r7
                            coginit r0 wc,wr
            if_b            neg r0, #1                         '' if C is set, return -1
                            // Temporary hack until fix for GCC is released
    #ifdef __PROPELLER_CMM__
                            lret
    #else
                            mov pc, lr
    #endif
    

    It feels like there should be a simpler way to do this - I can't be the first person trying to port a bunch of existing PASM cogs to PropGCC. If the use_cog_driver / load_cog_driver macros worked, that'd be a lot easier than having to know the GCC token asm blob above.
  • David BetzDavid Betz Posts: 14,516
    edited 2015-10-14 00:56
    So far I've just used the Spin compiler to compile PASM objects and then linked them with C code. I've never tried converting them to .S files first.

    Edit: By the way, I agree that this should be documented better.
  • David Betz wrote: »
    JasonDorie wrote: »
    Side question - Is SimpleIDE development continuing? I was under the impression that it was open source, but I can't find it now that Google Code is offline.. Was toying with the idea of poking around in there.
    Yes, it is open source. I'm not sure where jazzed has it located now that Google Code is gone. I'll check with him and let you know.
    A read-only copy is here: https://code.google.com/p/propside/

    I'm not sure where the most current sources are. Possibly, only on jazzed's hard drive.
  • JasonDorie wrote: »
    Does the load_cog_driver() macro basically resolve to the same thing as this?

    Nope. It actually expands to two different things depending on whether you're using an XMM mode or not. If not, it's this:
    /**
     * @brief Make the load symbols available for a driver
     * @param id The COG driver name
     */
    #define use_cog_driver(id)     extern uint32_t binary_##id##_dat_start[]
    
    /**
     * @brief Get a hub memory buffer containing a driver image
     * @param id The COG driver name
     */
    #define get_cog_driver(id)     (binary_##id##_dat_start)                              \
                    
    /**
     * @brief Load a COG driver
     * @param id The COG driver name
     * @param param Parameter to pass to the driver
     * @returns the id of the COG that was loaded
     */
    #define load_cog_driver(id, param) cognew(binary_##id##_dat_start, (uint32_t *)(param))
    

    The XMM version is longer, but you can find it on line 285 in <install dir>/propeller-elf/include/propeller.h
Sign In or Register to comment.