Shop OBEX P1 Docs P2 Docs Learn Events
Going nuts! What am I doing wrong? - Page 2 — Parallax Forums

Going nuts! What am I doing wrong?

2»

Comments

  • photomankcphotomankc Posts: 943
    edited 2012-08-12 20:34
    Is it just by virtue of being so many bytes ahead of the mailbox pointer. Looking at the code I can't see any mention of the stack beyond the declaration of the array inside the par_s structure and the cog gets passed "&m_par.Mailbox". So does the cog then just start using addresses above the pointer it's passed as stack?
  • jazzedjazzed Posts: 11,803
    edited 2012-08-12 23:05
    photomankc wrote: »
    Is it just by virtue of being so many bytes ahead of the mailbox pointer. Looking at the code I can't see any mention of the stack beyond the declaration of the array inside the par_s structure and the cog gets passed "&m_par.Mailbox". So does the cog then just start using addresses above the pointer it's passed as stack?

    Yes.

    The best documentation we have at the moment for COGC drivers is this: http://code.google.com/p/propgcc/wiki/COGModeExperiences

    There is a brief reference to COGC here: https://sites.google.com/site/propellergcc/documentation/libraries/propeller-h-library#TOC-cognew

    The stack approach is similar for starting a new LMM COG process: https://sites.google.com/site/propellergcc/documentation/libraries/propeller-h-library#TOC-cogstart

    Seems to me this subject deserves better treatment.
  • photomankcphotomankc Posts: 943
    edited 2012-08-13 07:04
    Alright I think this may indeed explain a lot. I replaced the i2cStretchHold function with copy/pasted loops and it looks like that removed the sp references from the original leaf functions. That alone did not get rid of the problems. Next I redesigned the structures to make sure that 16 longs are reserved above the pointer passed to cogstart. That did allow the -Os compiler optimization level executable to run which was failing before. Looking at the disassembly there are still some stack operations being generated by what I think are the intermediate results from putting the bytes of the register into the array to send them.

    Now I know I need to be looking at that so I'll watch out for that. It would explain why simply adding a few more operations to a function causes it weird out when the cog barfs over the hub memory it's using.

    Thanks guys, at least I have something that makes sense to go on.


    Last question. The address of stuff on the stack... are the addresses just 0x0000-0x8000 (minus the other stuff)? So if my address is 24,444 does that literally mean that 24K is already used? Looking at my variables in main they all seem to be starting around 0x5FXX and start incrementing from there. Sorry if this is explained somewhere I haven't read yet.
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-13 07:28
    photomankc wrote: »
    Last question. The address of stuff on the stack... are the addresses just 0x0000-0x8000 (minus the other stuff)? So if my address is 24,444 does that literally mean that 24K is already used? Looking at my variables in main they all seem to be starting around 0x5FXX and start incrementing from there. Sorry if this is explained somewhere I haven't read yet.
    The stack is always in hub memory and hub memory is address naturally as if accessed through the rdlong/wrlong instructions, etc. In fact this applies to both hub RAM and ROM. The address map that GCC uses starts with hub RAM at 0x0000 to 0x7fff, then hub ROM at 0x8000 to 0xffff. The full memory map is as follows:
    0x00000000-0x00007fff hub RAM
    0x00008000-0x0000ffff hub ROM
    0x20000000-0x2fffffff external RAM (XMM only)
    0x30000000-0xbfffffff external ROM (XMM only)
    0xc0000000-0xffffffff EEPROM COG images (LMM mode only for now)
    
  • jac_goudsmitjac_goudsmit Posts: 418
    edited 2012-08-13 08:08
    I will probably generate some documentation from my own experiences, but here are some things that threw me off at first:

    I thought at first that the function that was on top of a .cogc module was supposed to be the top-level function. When I tried to add more functions to my .cogc module, I noticed from the assembly listing that the compiler would rearrange the functions, which (if my assumption would have been right) would mean that the code would be executed in the wrong order. So then I thought (wrongly) that a .cogc module was limited to one function.

    Another wrong assumption was that I had to give the .cogc (top level) function a name that wouldn't clash with the other functions or other globals in the executable. It took me a while before I realized that the reason that the Toggle example compiled fine but my code didn't, was that I had named my .cogc function something other than main( ) so it wouldn't clash with the main( ) function in another module. The error message: "relocation truncated to fit: R_PROPELLER_SRC against symbol `_main' defined in .text section" didn't really help solve the problem: I thought there was something wrong with my program's main( ) function.

    So, here are some important things to know about writing a program with one or more .cogc modules:
    • In PASM, execution starts at the top of the code listing. But in C (.cogc modules), execution starts with the main( ) function which should be declared as _NATIVE void main(void *);
    • The compiler will not confuse the main( ) function in your .cogc modules with the main( ) function that's used as the top level function of your program.
    • When using cognew or coginit to start a cog for a .cogc module, you should use the __load_start_modulename_cog symbol as address. This is automatically generated by the compiler and must be declared as extern unsigned __load_start_modulename_cog[ ];. This is the address of the C runtime startup code (commonly known as crt0) which is stored at the start of the cog.
    • The startup code that's placed at the start of the cog initializes the .bss area of the cog. In C and C++, static variables are initialized to 0 before main starts; this is also true for _COGMEM variables before the cog's main( ) function starts, even though the program's main( ) function may already be running.
    • It is not possible to do e.g. __asm__ __volatile__("jmp #0") to restart a cog that runs C code: the pseudo-registers take up the same space as the initialization code so the initialization code cannot be run twice because it's overwritten by register values. If it's necessary to restart the cog without doing coginit( ) or cognew( ), you have to put a loop in your cog's main( ) function.

    As I said, I'll expand on this in the future.

    I'm also doing a lot with inline assembler which to me is the most valuable aspect of Prop-GCC and SimpleIDE: the possibility of mixing very tightly written Assembler with high-level C (or C++) code and run it in the same cog. I'll probably generate some documentation for that as well, because there really isn't a lot of it available right now.

    ===Jac
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-13 08:27
    • In PASM, execution starts at the top of the code listing. But in C (.cogc modules), execution starts with the main( ) function which should be declared as _NATIVE void main(void *);
    Actually, the main function should be declared _NAKED and it should never return.
  • jac_goudsmitjac_goudsmit Posts: 418
    edited 2012-08-13 09:37
    David Betz wrote: »
    Actually, the main function should be declared _NAKED and it should never return.

    I saw the requirement about declaring main _NAKED earlier today on some other page and I think that page is wrong. The cog_c_toggle sample has it declared as _NATIVE and so do I, and both work fine.

    Also I had a look at the crt0 code and it calls main with a regular CALL instruction (not a jmp) so main is allowed to return. After it returns, the crt0 code calls __exit which is basically cogid r1 / cogstop r1. In other words: if you return from main in a .cogc module, the cog stops. (Hey, I can add that to the list :-)

    Edit: I wonder if _NAKED and not being able to return are related? What does _NAKED do exactly?

    Edit: I'll copy my message into a new thread - sorry for hijacking this one :-)

    ===Jac
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-13 10:30
    I saw the requirement about declaring main _NAKED earlier today on some other page and I think that page is wrong. The cog_c_toggle sample has it declared as _NATIVE and so do I, and both work fine.

    Also I had a look at the crt0 code and it calls main with a regular CALL instruction (not a jmp) so main is allowed to return. After it returns, the crt0 code calls __exit which is basically cogid r1 / cogstop r1. In other words: if you return from main in a .cogc module, the cog stops. (Hey, I can add that to the list :-)

    Edit: I wonder if _NAKED and not being able to return are related? What does _NAKED do exactly?

    Edit: I'll copy my message into a new thread - sorry for hijacking this one :-)

    ===Jac
    Yes, I think that _NAKED does have to do with not being able to return from main() but maybe Eric can give us more details.
  • ersmithersmith Posts: 6,054
    edited 2012-08-13 11:09
    _NAKED says that a function does not need to save any registers and will not return. _NATIVE says the function is called with a traditional CALL instruction.

    It's OK to declare main _NAKED in a COG C program, provided it never returns. Indeed it's probably a good idea, since it will save a little bit of space (any register saving/restoring code). But it's not required.

    Eric
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-13 11:23
    ersmith wrote: »
    _NAKED says that a function does not need to save any registers and will not return. _NATIVE says the function is called with a traditional CALL instruction.

    It's OK to declare main _NAKED in a COG C program, provided it never returns. Indeed it's probably a good idea, since it will save a little bit of space (any register saving/restoring code). But it's not required.

    Eric
    Won't the register saving/restoring involve stack accesses? If so, using _NAKED is probably mandatory for any COG C program that wants to run without a stack.
  • ersmithersmith Posts: 6,054
    edited 2012-08-13 12:48
    David Betz wrote: »
    Won't the register saving/restoring involve stack accesses? If so, using _NAKED is mandatory for any COG C program that wants to run without a stack, right?

    Not necessarily -- if the main function happens not to need to save and restore registers then _NATIVE will work just as well as _NAKED. I do think _NAKED is probably a good idea, but it's not mandatory.
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-13 13:01
    ersmith wrote: »
    Not necessarily -- if the main function happens not to need to save and restore registers then _NATIVE will work just as well as _NAKED. I do think _NAKED is probably a good idea, but it's not mandatory.
    Okay, thanks for clarifying _NAKED and _NATIVE. By the way, I believe these are probably documented in the Propeller-specific part of the GCC document. Is that correct? If so, is there any easy way we could extract the Propeller-specific section and post it to the beta forum separately. It's kind of hard to find that information buried in the GCC document. It might be nice to have it also available separately.

    Thanks,
    David
  • jac_goudsmitjac_goudsmit Posts: 418
    edited 2012-08-14 07:27
    Soooooo.... Just wondering...

    Let's say my code uses _NATIVE (not _NAKED) and I'm using a pointer to a struct in the hub as my PAR.

    First of all: I noticed crt0 initializes SP to PAR, so does that mean my hub struct gets trashed if I use a stack?

    Secondly: How do I know if the compiler decided to save the registers in the .cogc main function?

    Thirdly: Is a stack also needed if my .cogc main( ) calls other functions? Or only if they use more than (let's say) 15 parameters (one in each pseudo register)?

    Dang I thought I was "getting it", now I'm not so sure :-)
    Need input! :-)


    ===Jac
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-14 07:33
    Soooooo.... Just wondering...

    Let's say my code uses _NATIVE (not _NAKED) and I'm using a pointer to a struct in the hub as my PAR.

    First of all: I noticed crt0 initializes SP to PAR, so does that mean my hub struct gets trashed if I use a stack?
    No, your hub struct will not get trashed because the stack will grow from that point down in memory not up. That is why you need to pass a pointer to something like this:
    struct {
      long stack[STACK_SIZE];
      struct {
        // parameters for your COG C code
      } my_param_struct;
    } init_struct;
    

    Then you pass &init_struct.my_param_struct as your parameter.
    Secondly: How do I know if the compiler decided to save the registers in the .cogc main function?
    The only way I've found to do this is to look at the disassembly of the compiled code. Use propeller-elf-objdump -d.
    Thirdly: Is a stack also needed if my .cogc main( ) calls other functions? Or only if they use more than (let's say) 15 parameters (one in each pseudo register)?
    You can call one level of _NATIVE functions called from your main code without requiring a stack most of the time but you really need to check the disassembly to make sure no stack operations were generated. It's a pain but I don't know of another way to be sure.
  • photomankcphotomankc Posts: 943
    edited 2012-08-14 08:25
    It would be nice if the compiler warned you that HUB stack calls were created in a case where you are saying they shouldn't be but I say that having no idea how difficult that is to implement. I am having a real tough time finding a way to arrange the code so it stops using HUB stack when I have to reorder the word variables to get it sent out high-byte first but that I can live with for now. I definately wanted them gone between the clock pulses though. No way I want it trying to access HUB memory in that location.

    Has anyone got that perl script for the map file to run on a Windows 7 box? Whenever I try to it only hangs and chews up all availible memory up to whatever the system has installed. 2PCs tried so far.




    BTW: That (COG Stack) seems to have cleared up the weirds now. I'm getting proper behaviour for all the optimizer levels now.

    So, If I can ever figure out a way to do the math needed to really use this thing without floating point I'll be back in business.
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-14 08:30
    photomankc wrote: »
    It would be nice if the compiler warned you that HUB stack calls were created in a case where you are saying they shouldn't be but I say that having no idea how difficult that is to implement.
    I asked for that feature as soon as I ran into this problem but was told that it would involve changes in the machine-independent part of GCC. Normally, one only writes a new code generator for a target machine. Changing the basic GCC infrastructure code is a much bigger effort and would need to be negotiated with the OSS GCC developers if it was to be folded into the mainstream GCC code base.
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-14 08:39
    photomankc wrote: »
    Has anyone got that perl script for the map file to run on a Windows 7 box? Whenever I try to it only hangs and chews up all availible memory up to whatever the system has installed. 2PCs tried so far.
    You mean you tried something like this:
    propeller-elf-objdump -d foo.elf >foo.lst
    

    And that filled all available memory?
  • jac_goudsmitjac_goudsmit Posts: 418
    edited 2012-08-14 09:17
    David Betz wrote: »
    No, your hub struct will not get trashed because the stack will grow from that point down in memory not up. That is why you need to pass a pointer to something like this:
    struct {
      long stack[STACK_SIZE];
      struct {
        // parameters for your COG C code
      } my_param_struct;
    } init_struct;
    

    Then you pass &init_struct.my_param_struct as your parameter.

    What I was saying is that my struct did NOT have a stack[ ] array as parameter, only a struct with data. So the answer is not no but YES, there should definitely be a stack at *par. Understood.

    The only way I've found to do this is to look at the disassembly of the compiled code. Use propeller-elf-objdump -d.

    I've been using the built-in option of right-clicking a source file and selecting "Show Assembly". Works great!
    You can call one level of _NATIVE functions called from your main code without requiring a stack most of the time but you really need to check the disassembly to make sure no stack operations were generated. It's a pain but I don't know of another way to be sure.

    That must be how I got away with it so far: I only have one level of calls in my .cogc module :-)

    Side* remark: Too bad that so much PASM knowledge is needed to start programming in C/C++. Not a problem for me but I can see how it might be a problem for others.

    ===Jac

    (*No pun intended)
  • photomankcphotomankc Posts: 943
    edited 2012-08-14 09:20
    No, there's a perl script, and I dont have the command line syntax handy at the moment that takes the foo.map file and is supposed to summerize the sections and report the totals in decimal rather than in hex. Running that on the .map files I have with ActivePerl installed and the CPU use hits about 50% and memory use just continues to increase until I kill the process. On one box I let it continue past 2.5G of memory allocated to the process without it ever completing.
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-14 09:21
    What I was saying is that my struct did NOT have a stack[ ] array as parameter, only a struct with data. So the answer is not no but YES, there should definitely be a stack at *par. Understood.




    I've been using the built-in option of right-clicking a source file and selecting "Show Assembly". Works great!



    That must be how I got away with it so far: I only have one level of calls in my .cogc module :-)

    Side* remark: Too bad that so much PASM knowledge is needed to start programming in C/C++. Not a problem for me but I can see how it might be a problem for others.

    ===Jac

    (*No pun intended)
    If you don't have a stack in the structure you pass as a parameter then your structure won't get trashed by the COG code. The data that comes immediately before it in memory will get trashed.
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-14 09:23
    Side* remark: Too bad that so much PASM knowledge is needed to start programming in C/C++. Not a problem for me but I can see how it might be a problem for others.
    It's only really required if you want to use the COG memory model and don't want to supply the COG C code with space for a stack. If you do supply a stack or if you use the LMM or XMM memory models then you don't really need to worry about the generated assembly code.
  • photomankcphotomankc Posts: 943
    edited 2012-08-14 09:27
    David Betz wrote: »
    If you don't have a stack in the structure you pass as a parameter then your structure won't get trashed by the COG code. The data that comes immediately before it in memory will get trashed.


    Yeah.... ask me how I learned that! :) What was even more fun was the PAR pointer was to a structure scoped inside a constuctor. So the bytes above that were just some anonymous bytes on the stack patiently waiting for some function to grow back into them and allow entertainment to ensue.
  • David BetzDavid Betz Posts: 14,516
    edited 2012-08-14 09:33
    photomankc wrote: »
    Yeah.... ask me how I learned that! :) What was even more fun was the PAR pointer was to a structure scoped inside a constuctor. So the bytes above that were just some anonymous bytes on the stack patiently waiting for some function to grow back into them and allow entertainment to ensue.
    Yes, stack corruption bugs can definitely provide a lot of "entertainment".
  • jac_goudsmitjac_goudsmit Posts: 418
    edited 2012-08-14 09:39
    David Betz wrote: »
    If you don't have a stack in the structure you pass as a parameter then your structure won't get trashed by the COG code. The data that comes immediately before it in memory will get trashed.

    Oh, now I see what you were saying, the stack grows downward from PAR. Got it. Makes sense too.

    ===Jac
  • frank freedmanfrank freedman Posts: 1,983
    edited 2012-10-27 16:24
    Sorry to reopen an old thread, but it was the only thread that came up when I used google to search for the answer to this build failure.

    relocation truncated to fit: R_PROPELLER_SRC against 'myvar'.

    I finally figured it out that I had called and named the module clockgen rather than cogclockgen for a .S file that would be loaded into its own cog. Not sure of the mechanism of this behavior, but it took a little while to realize what I had done. Figured 1) if anyone else had this result from this particular oops they would not spend an hour running it down, and 2) maybe someone can enlighten as to why the message is generated.

    Thanks,

    Frank
  • ersmithersmith Posts: 6,054
    edited 2012-10-28 15:33
    Sorry to reopen an old thread, but it was the only thread that came up when I used google to search for the answer to this build failure.

    relocation truncated to fit: R_PROPELLER_SRC against 'myvar'.
    This means that the source value in some instruction (most likely a jmp) does not fit in 9 bits. In your case since you had forgotten to use ".cog" in a section name it arose because the assembly got placed by the linker after the rest of the LMM program, with addresses in LMM space. Unless you have a very tiny program indeed these addresses will be bigger than 512, and hence any jumps or similar references to labels in the code will overflow the space available in the instruction.

    Eric
Sign In or Register to comment.