Shop Learn
Propeller gcc/gnu assembler alignment issue. — Parallax Forums

Propeller gcc/gnu assembler alignment issue.

Hi,

I'm using the command line tools for propeller GCC under linux. I compiled the package last year (propeller-elf-gcc 4.6.1), and have been porting C programs to propeller1, and some assembly programs from Catalina. I have put timing critical assembly programs for stand alone operation in a cog into .S files, but I am having a problem with gcc/gnu assembler computing cog ram addresses wrong.
eg: in code like:
   ...
Command       rdlong    IOj, par                     ''#2/3 Get command# if any.
                        and       IOj, #$C                     ''4   LS nybble, multiple of 4.
                        add       IOj, #Command        ''5   Table starts with Command
                        jmp       IOrj                            ''6   do multitasking, will return to address in IOj

ReadSetup     rdlong    localCmd,par          ''#2/3
                       shr       localCmd,#4             ''4
                       mov       IOj, #readIndex       ''5 
                       jmp       IOrj                            ''6 do multitasking, will return to address in IOj

WriteSetup    ...

The idea is that the index is loaded from hub ram and a computed goto is to be done.
But, I often get a "relocation truncated to fit: R_PROPELLER_SRC_IMM against 'Command', etc. when I try to compile programs like this.

I tried using the directive .cog_ram at the top of my .S file, but gcc complains the directive is not known.
I can do mova, to get correct addresses for generic moves; but how do I make that happen for addition, subtraction, and other operations?

Comments

  • altosackaltosack Posts: 131
    edited 2015-10-10 10:08
    .cog_ram is deprecated. Use .pasm instead.

    Welcome to the propgcc .S club ! For some reason the atmosphere is rarified, but #define, #ifdef, etc, are tools that I don't want to do without, and I'm not sure why it's a dirty little secret that it works in pasm as well as C, even allowing you to #define something in a header that's referred to in both C & pasm.

    The only problem I've had is that arithmetic is not supported in the .float directive (e.g., .float MY_CONSTANT * MY_FACTOR). My workaround for that is to define it in hub (lmm or cmm C) and read it in from the cog (.S) . It's a bit wasteful and not very elegant, but it works.
  • Oh, I see. Thanks. That solves the problem.

    I just noticed I have a note in my code commenting out .pasm at the top of the file, dated to a time from before I changed to the command line version of GCC. I also have a commented out fcache directive in the same place.
    I was working with simple IDE 1.0 at the time I comment those out, because it didn't like either of those directives.
    I take it simpleIDE 1.0 uses the old .cog_ram directive ? Is there a way to detect simple IDE 1.0 using #if statements so the code will port to simple IDE, or has simple IDE been upgraded yet with a new release, capable of accepting the newer directives?

    On a different note; Yes, I can see that not a whole lot of people are writing .S files for C programs.
    :) -- I'm doing using capital .S files exactly for the purpose you're talking about; allowing me to use pre-processor macros.

    When I write a library, I make three files; A C interface file, a header file, and an assembly language .S file.
    A single header file is shared between the pasm .S file and the C interface library.

    In the assembly file, I #define ASSEMBLY right before #including the header file so I can conditionally remove all C code in the header with #ifndef ASSEMBLY statements. That allows me to have a single header file define all the compile time constants that both the C interface program and the assembly language program share in common.

    That method saves a lot of maintenance headaches.
  • The #ifndef ASSEMBLY is exactly what I do; I think some variant of that is automatically defined by gcc itself when it parses a .S file, but I can't remember what it is, so I do it myself, like you, just to be sure.

    I'm not sure what the fcache would be doing in a cog file; it should only be used with functions in the hub.

    I don't know how to detect the propgcc version, or what version it changed from .cog_ram to .pasm. ersmith and Dave Betz would be the people to ask.
  • DavidZemonDavidZemon Posts: 2,937
    edited 2015-10-14 02:22
    propeller-elf-as v2.31.1 first introduced .pasm. I don't recall exactly which version of PropGCC packaged that assembler. I also know that no SimpleIDE package has been released with a new enough PropGCC package. I do know you can find links to the most up-to-date versions of PropGCC in the "propgcc now in the parallax github" forum thread.
  • FastrobotFastrobot Posts: 51
    edited 2015-10-13 00:25
    I see, well, I'll just have ignore simpleIDE then.

    Also, I'm trying to debug my library now. I'm running gnu debugger on the C program which calls the interface to the assembly language COG program. I know GDB can't access the processor ram that the assembly program is running in because it's in a separate COG, but I'd like to be able to at least examine the io pins on the parallax chip. Is there a direct way to get GDB to print the ina port?
    I compiled everything with -g and -ggdb3, and it knows about the macro expansions; but I get this:
    (gdb) print INA
    No symbol "_INA" in current context.

    If I try to be sneaky, and create a function to look at the ports like:
    int gdbina(void) {return INA;}
    int gdbouta(void) {return OUTA;}
    int gdbdira(void) {return DIRA;}
    
    int main(void) {
    // All static variables, being in BSS, are presumed zeroed by C startup.
    // All chip initialization is done here, in main.
    
    	int tmp = gdbina()+gdbouta()+gdbdira();	// Don't let dummy functions get optimized out
           ...
    

    Doing a print gets a different error:
    (gdb) print gdbina()

    Breakpoint 1, main () at trajectoryqueue.c:166
    166 M( com1, init, 27, 26, 0, 9600 );
    The program being debugged stopped while in a function called from GDB.
    Evaluation of the expression containing the function
    (gdbina) will be abandoned.
    When the function is done executing, GDB will silently stop.

    EDIT: If I clear the breakpoint, the error message goes away, but the function is never executed. So this is a GDB bug, apparently GDB doesn't change the program counter address to the function call, but erroneously tries to continue from last PC address as if "continuing" the program... drat. :(

    I also can't take the addres of a global register in the program; saying "unsigned int* temp=&_INA;" won't compile. So COG ram addresses can't ever be accessed by pointers...?

    Does anybody know how can this be worked around so I can examine the IO pins on the fly with GDB?
    Is there a way to get the GDB monitor program to return the value of a cog register?
  • FastrobotFastrobot Posts: 51
    edited 2015-10-13 00:04
    altosack wrote: »
    I'm not sure what the fcache would be doing in a cog file; it should only be used with functions in the hub.

    Blocks of hub ram can be loaded partially from external serial eeprom.
    I haven't seen any documentation as to how the processor knows how much memory to load when a request for access to a pointer is given. fcache is supposed to inform the compiler that the entire block of memory must be loaded together, and not segmented. I don't know if fcache is needed or not, but as the cognew() function must read from hub ram and can't be stopped or interrupted once begun, there is a risk that if not all of a .S program program was loaded into hub ram simultaneously, that launching a cog will download a corrupt image.

    When in doubt, I think attempting to use a directive like fcache is preferable to guessing about undocumented behavior.
  • FastrobotFastrobot Posts: 51
    edited 2015-10-13 01:09
    And one more bit of gdb bizarre behavior.... I'm definitely having a bad day.
    In my program, I define a pointer:

    long *i=(long*)(void*)self; // self is a data structure that I wish to initialize as if it were a long array.

    *i=(long)(void*)self->m.tx-buffer; // some value
    *++i=(long)(void*)self->m.rx_buffer; // some value
    *++i=0xffff0000; // I break the program here to look at it with GDB.

    Now watch what happens when I ask for various bits of information...
    (gdb) print /x *i
    $70 = 0xffff0000 # Very good, exactly what the value ought to be.
    (gdb) print i
    $71 = (long int *) 0x6064  # So that's the hub ram address that the data is stored in.
    (gdb) print /x (long[2])i
    $72 = {0x6064, 0x6044}  # This is weird.. I didn't expect that first value...
    (gdb) print /x *(long[2])i
    $73= 0x6064 # In C, this ought to be the first element of the array, not a pointer to the array.
    (gdb) print /x **(long[2])i
    $74 = 0xffff0000 
    (gdb)
    

    Why is this happening? I expect that a single dereferencing * applied to an array ought to return the first element of the array, not the pointer to the array.
Sign In or Register to comment.