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

PropGCC / PASM question

2456

Comments

  • So I have the first part (the RC_Receiver) working - tested on the real hardware and everything! Now I'm trying to port the next driver, and running into new issues.

    The next driver is my high-res Servo32 object, and it compiles fine, but I'm getting the following messages when I link:
    cmm/Servo32_HighRes_driver.o: In function `CreateServoArray':
    (Servo32.cog+0x7c): relocation truncated to fit: R_PROPELLER_SRC_IMM against `ServoPins'
    cmm/Servo32_HighRes_driver.o: In function `CreateServoArray':
    (Servo32.cog+0x80): relocation truncated to fit: R_PROPELLER_SRC_IMM against `ServoDelays'
    cmm/Servo32_HighRes_driver.o: In function `PassLoop':
    (Servo32.cog+0xc8): relocation truncated to fit: R_PROPELLER_SRC_IMM against `ServoDelays'
    cmm/Servo32_HighRes_driver.o: In function `PassLoop':
    (Servo32.cog+0xd0): relocation truncated to fit: R_PROPELLER_SRC_IMM against `ServoDelays'
    

    Any ideas as to what that means or why it's happening? This is a direct port of an existing PASM routine from a working project, so I'm hoping this is just a syntax issue.

    I've attached the sources, and the script I'm using to build it. You'll need to have propeller-gcc in your path, and change the LIBS variable in the script to match your local path settings, but it should be relatively painless.

  • I created those macros to allow the same code to work under both the CMM/LMM and XMM memory models. In the case of XMM, the COG image has to be copied from external memory to hub memory before it can be loaded into a COG.
  • Re: "relocation truncated to fit"

    You might check this out: http://forums.parallax.com/discussion/comment/1117690/#Comment_1117690

    I've hit that error too, though not in quite a while. I think it means a jump instructions is trying to jump to an address which is out-of-range (say you wan to jump 512 bytes ahead, but you only have 8 bits of address range - that kind of thing).
  • ...but this is a PASM driver, written in native code that runs fine in other projects. It shouldn't need to re-interpret anything, should it?
  • JasonDorie wrote: »
    ...but this is a PASM driver, written in native code that runs fine in other projects. It shouldn't need to re-interpret anything, should it?
    Typically, you can get a PASM driver that uses a mailbox interface working pretty easily by just rewriting the Spin interface code in C and then compiling the Spin code to extract the DAT block containing the PASM code. I think this is what SimpleIDE does with a .spin file. However, I've never really used SimpleIDE. This is based on discussions I had with Steve when he was developing it.

  • I'll have to try that. I do a bunch of pre-init of DAT section variables in a few of my objects, which I suspect will complicate matters, but I can probably rework that if necessary.

    Thanks for all the help.
  • JasonDorie wrote: »
    I'll have to try that. I do a bunch of pre-init of DAT section variables in a few of my objects, which I suspect will complicate matters, but I can probably rework that if necessary.

    Thanks for all the help.
    BTW, I'm not sure it's completely accurate to say you can't share COG variables with C code. As I've mentioned before, Eric has a way of linking COG code with C code that allows symbols to be accessed from the C code. Unfortunately, I can't recall how that is done. You might want to ask him.

  • I think in a .sx file you can declare labels as global, and then extern them from the C side, but that's in the object I still haven't been able to get to link, so I can't say for sure that it works yet.
  • JasonDorie wrote: »
    I think in a .sx file you can declare labels as global, and then extern them from the C side, but that's in the object I still haven't been able to get to link, so I can't say for sure that it works yet.
    If you just link a .sx file with your C code you'll end up with LMM assembly code not something that runs in a COG.

  • I've added the Spin files to the project, and they do indeed compile. If I use the following macros, everything links, but it hangs when it hits this code:
    void RC_Start(void)
    {
      use_cog_driver(RC_Receiver_driver);
      load_cog_driver(RC_Receiver_driver, &RC_Pins[0]);
    }
    

    Are there any examples that do this anywhere?
  • JasonDorie wrote: »
    I've added the Spin files to the project, and they do indeed compile. If I use the following macros, everything links, but it hangs when it hits this code:
    void RC_Start(void)
    {
      use_cog_driver(RC_Receiver_driver);
      load_cog_driver(RC_Receiver_driver, &RC_Pins[0]);
    }
    

    Are there any examples that do this anywhere?
    Check with Andy Lindsay at Parallax. He and Steve put all of the SimpleIDE examples together. I wasn't involved.

  • I think I spoke too soon. It looks like it was a misunderstanding on my part of how pause() works. I've switched my main loop to waitcnt() and it appears to be working with the RC Receiver object. About to try the Servo object again. If that works as expected this might end up being easier than I thought.

    Thanks again for all the help!
  • One of the objects works, the other appears to hang, like it's dying on a waitcnt somewhere in the code, which makes no sense. I've spent a few hours banging at it to no avail. I'll try again after work maybe.
  • Ok, this one was all me - I made a Spin version of the code I was using to upload it and it turns out one of the methods I was using in my test was busted, and of course I wasn't using that method in the real project, so I now have two objects ported and working, and all the grief in the case of the 2nd one was my own.

    I'm going to keep working on this tonight and see how far I get.
  • JasonDorie wrote: »
    Ok, this one was all me - I made a Spin version of the code I was using to upload it and it turns out one of the methods I was using in my test was busted, and of course I wasn't using that method in the real project, so I now have two objects ported and working, and all the grief in the case of the 2nd one was my own.

    I'm going to keep working on this tonight and see how far I get.
    Great news! I'm glad you found the problem.

  • Porting my next object I ran into a case where parsing from Spin files is less desirable than from .sx files. I have a Spin object that includes a bunch of project-wide constants, and they're used in both PASM and in Spin. In the C version of the project, they'd be in a header file as #defines, but I can't include that from a Spin file, so now I'd need two copies of the consts.

    I realize this is probably as much a SimpleIDE issue as a PropGCC one, but I figured it was worth passing along. Being able to use .sx files in SimpleIDE, and having the same ease of linkage as with the Spin file version would be very useful.
  • JasonDorie wrote: »
    Porting my next object I ran into a case where parsing from Spin files is less desirable than from .sx files. I have a Spin object that includes a bunch of project-wide constants, and they're used in both PASM and in Spin. In the C version of the project, they'd be in a header file as #defines, but I can't include that from a Spin file, so now I'd need two copies of the consts.

    I realize this is probably as much a SimpleIDE issue as a PropGCC one, but I figured it was worth passing along. Being able to use .sx files in SimpleIDE, and having the same ease of linkage as with the Spin file version would be very useful.
    Yeah, that sort of stuff is not seamless. Not sure how it could be made to be seamless unless we write a utility that will parse Spin files and output a C header file.
  • Hmm - here's an interesting one. Take a look at the attached object. Near the end of the file is a table called cmdCallTable - It's a list of jmpret instructions whose addresses are resolved by the Spin compiler. I need access to that table to generate my command stream. Is there a way to get that symbol accessible from C?
  • JasonDorie wrote: »
    Hmm - here's an interesting one. Take a look at the attached object. Near the end of the file is a table called cmdCallTable - It's a list of jmpret instructions whose addresses are resolved by the Spin compiler. I need access to that table to generate my command stream. Is there a way to get that symbol accessible from C?
    That's the sort of thing that Eric's method of linking in drivers is supposed to handle. I'll see if I can find an example of his method.
  • Here is the Makefile rule for creating a .o file containing a COG image that can be linked with your main program. Any symbols in the COG image will be visible to the main program.
    #
    # a .cog program is an object file that contains code intended to
    # run in a COG separate from the main program; i.e., it's a COG
    # driver that the linker will place in the .text section.
    #
    %.cog: %.cogc
    	propeller-elf-gcc -Os -mcog -xc -r -o $@ $<
    	propeller-elf-objcopy --localize-text --rename-section .text=$@ $@
    
    The problem is, this only works with C code and maybe with GAS code. It doesn't work with PASM extracted from Spin files because GCC has no idea about Spin or PASM symbols.
  • I punted for the moment. In my C startup code, I do this:
      uint32_t * driverMem = get_cog_driver(F32_driver);
      int i=0;
      while( driverMem[i] != 0x12345678 )
        i++;
    
      cmdCallTableAddr = (int *)driverMem + i + 1;
    

    And in the Spin cog source, I put $12345678 immediately before my jump table. It ain't pretty, but it works.
  • JasonDorie wrote: »
    I punted for the moment. In my C startup code, I do this:
      uint32_t * driverMem = get_cog_driver(F32_driver);
      int i=0;
      while( driverMem[i] != 0x12345678 )
        i++;
    
      cmdCallTableAddr = (int *)driverMem + i + 1;
    

    And in the Spin cog source, I put $12345678 immediately before my jump table. It ain't pretty, but it works.

    Ha! I love it :D
  • JasonDorie wrote: »
    I punted for the moment. In my C startup code, I do this:
      uint32_t * driverMem = get_cog_driver(F32_driver);
      int i=0;
      while( driverMem[i] != 0x12345678 )
        i++;
    
      cmdCallTableAddr = (int *)driverMem + i + 1;
    

    And in the Spin cog source, I put $12345678 immediately before my jump table. It ain't pretty, but it works.
    This is pretty much exactly what Jeff Martin did to do something similar with his Wi-Fi loader code.

  • JasonDorieJasonDorie Posts: 1,930
    edited 2015-10-15 22:38
    Here's another one:
    static long gx;
    
    unsigned short QuatUpdateCommands[] = {
            F32_opFloat,
            &gx,
            0 };
    

    I get this error:
    QuatIMU.c:492:9: error: initializer element is not computable at load time

    Is PropGCC unable to compute hub addresses at compile time? That was one of those things I was really looking forward to over Spin. If it can't resolve pointers at compile time, one of my modules just tripled in size because I'll have to write code to initialize a very large array at run time.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2015-10-15 22:52
    Ok, this is bizarre. This works:
    static int t[] = {
       (int)&gx, (int)&gy
     };
    

    ...but this doesn't:
    static unsigned short t2[] = {
        (int)&gx, (int)&gy
    };
    

    QuatIMU.c:251:5: error: initializer element is not computable at load time
    QuatIMU.c:251:5: error: (near initialization for 't2[0]')
    QuatIMU.c:252:1: error: initializer element is not computable at load time
    QuatIMU.c:252:1: error: (near initialization for 't2[1]')

    Why would casting to a different type matter?

    It means the size doubles instead of triples, which is better, but . . .
  • jmgjmg Posts: 15,173
    David Betz wrote: »
    Yeah, that sort of stuff is not seamless. Not sure how it could be made to be seamless unless we write a utility that will parse Spin files and output a C header file.
    David Betz wrote: »
    Here is the Makefile rule for creating a .o file containing a COG image that can be linked with your main program. ....
    The problem is, this only works with C code and maybe with GAS code. It doesn't work with PASM extracted from Spin files because GCC has no idea about Spin or PASM symbols.

    Sounds like ideally Spin should export Header and GAS source files, in order to make all this boundary crossing stuff easier ?
    GAS has .set and .equ for symbol defines, as well as .include (like any decent assembler), so it should be able to import exported files.
  • JasonDorie wrote: »
    Here's another one:
    static long gx;
    
    unsigned short QuatUpdateCommands[] = {
            F32_opFloat,
            &gx,
            0 };
    

    I get this error:
    QuatIMU.c:492:9: error: initializer element is not computable at load time

    Is PropGCC unable to compute hub addresses at compile time? That was one of those things I was really looking forward to over Spin. If it can't resolve pointers at compile time, one of my modules just tripled in size because I'll have to write code to initialize a very large array at run time.
    What is the type of F32_opFloat? The &gx expression should be okay.
  • JasonDorie wrote: »
    Ok, this is bizarre. This works:
    static int t[] = {
       (int)&gx, (int)&gy
     };
    

    ...but this doesn't:
    static unsigned short t2[] = {
        (int)&gx, (int)&gy
    };
    

    QuatIMU.c:251:5: error: initializer element is not computable at load time
    QuatIMU.c:251:5: error: (near initialization for 't2[0]')
    QuatIMU.c:252:1: error: initializer element is not computable at load time
    QuatIMU.c:252:1: error: (near initialization for 't2[1]')

    Why would casting to a different type matter?

    It means the size doubles instead of triples, which is better, but . . .
    Okay, maybe that's the problem. You are trying to use the lower 16 bits of a 32 bit value. The linker could fixup the initializer if it was the entire value but maybe it doesn't know how to do arithmetic on the 32 bit value to truncate it to 16 bits. Also, it can't figure these things out at compile time since the compiler produces relocatable object files. Only the linker knows what absolute hub address is assigned to a variable.
  • David Betz wrote: »
    BTW, I'm not sure it's completely accurate to say you can't share COG variables with C code. As I've mentioned before, Eric has a way of linking COG code with C code that allows symbols to be accessed from the C code. Unfortunately, I can't recall how that is done. You might want to ask him.

    Sharing variables between GAS/PASM code and C code is easy. Normally you'll want to put your PASM code that's intended to run in another COG into its own section, with a name that either starts or ends with .cog. The linker treats those specially and will automatically generate __load_start_xxx symbols for them (making it easy to load into the COG). Shared data should go into the .data section. Remember that C names will be prefixed with an underscore, so to access the C symbol "foo" from PASM you have to use "_foo".

    The gas_toggle demo shows how to do this; it has an example of a pin toggling program running on its own COG and reading C variables pins and wait_time to determine which pins to set and how long to wait between toggles.

    You can also use this method to share data between COGC and LMM, but it's slightly trickier than with assembler because the compiler normally wants to put C functions in the .text section, and also because the COGC code will need different library functions than the LMM code. Almost always you'll want to partially link the COGC code and resolve as many symbols as possible (using -r) and then use objcopy to rename the .text section into a name with .cog (like foo.cog). I think David has already posted an example of a command to do that. The cog_c_toggle demo is a complete example. It happens to use a mailbox, but it doesn't have to -- it could directly access variables in the main program instead.

    Eric
  • My current issue with using GAS/PASM is that it's not properly supported by SimpleIDE, and requires makefiles instead. Since the project is supposed to be a teaching tool, I'm trying to keep it easy to work with.
Sign In or Register to comment.