Propeller gcc/gnu assembler alignment issue.
Fastrobot
Posts: 51
in Propeller 1
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:
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?
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
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.
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.
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.
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:
If I try to be sneaky, and create a function to look at the ports like:
Doing a print gets a different error:
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?
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.
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...
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.