[SOLVED] Memory Layout around DAT blocks
Bobb Fwed
Posts: 1,119
I'm sure it is in the manual somewhere, but I can't seem to find it. I've been banging my head against my desk trying to figure this out...What information in memory comes before a DAT block?
I have a DAT declared before any code in my program. Yet the information stored there is stored at address $0190 when compiled. The software is pretty complex at about 25KB when compiled, and I can't quite figure out what comes before the DAT information to figure out a problem.
I've discovered a recent issue in the software where some EEPROM memory is being overwritten in one part of my program when my a value in my DAT is in a specific location (i.e. it seems everything is fixed when I move my value in DAT down in memory 1 long (or more). There is likely a memory overrun happening somewhere, and I'm trying to troubleshoot it. But it all seems to be caused by the location of my DAT value.
I have a DAT declared before any code in my program. Yet the information stored there is stored at address $0190 when compiled. The software is pretty complex at about 25KB when compiled, and I can't quite figure out what comes before the DAT information to figure out a problem.
I've discovered a recent issue in the software where some EEPROM memory is being overwritten in one part of my program when my a value in my DAT is in a specific location (i.e. it seems everything is fixed when I move my value in DAT down in memory 1 long (or more). There is likely a memory overrun happening somewhere, and I'm trying to troubleshoot it. But it all seems to be caused by the location of my DAT value.
Comments
When I am writing to a DAT area I usually use the label as a start address and an index as the offset from there to point to it in memory.
The first 16 bytes of hubram are a header that tells the Spin loader how to set stuff up on boot. Most of it can be reused after that, but note that long[0] is clkfreq and byte[5] is clkmode. After that is the header for the first Spin object. A Spin object's header contains things like the total length of the object's DAT and PUB/PRI memory (which also serves as an offset to the next object), an offset to that object's VARiables, and offsets/parameter counts for each Spin PUB/PRI method. Next comes all of that object's DAT variables, then all of its PUB methods, then all of its PRI methods, and finally pointers to its sub-objects. DAT data ends up before PUB and PRI data regardless of where you put it in the file. All offsets are relative to the current object's base address (pbase).
Your bug is likely because you're using @ in a DAT block. The @ operator compiles to more than "push this constant number onto the stack". It actually compiles to code that gets the base address of the current object (for a symbol in a DAT block), of the current VARiable (for a symbol in a VAR block), or of the current stack frame (for a local variable), and then adds an offset to that. Since the compiler doesn't know where each object will go when it's processing DAT blocks, it can't handle @ properly because it can't come up with a final address yet, so it instead outputs the offset of the symbol relative to the current object's base.
EDIT: Details about the Spin object format can be found at http://forums.parallax.com/discussion/download/115824/Propeller%20Spin%20Architecture.pdf.
This is the information I was looking for. Off the top of my head, it doesn't help me right now, but this bug is one of those pesky difficult-to-reproduce ones, the info may help me think of a solution once I mull over it some more. I think it's purely chance I am easily seeing the bug with my current version of the program. If I add one LONG to the program (in variable or code form) I can't recreate the bug any more. But that just means there's a good chance it's messing with memory somewhere I can't readily see. Thank you for answering my question. I will have to continue to explore how the memory is laid out to try to find the code that's causing the issue.
I am not using any @'s in my DAT blocks.
My guess is the added long makes the byte buffer long aligned which solves the problem for you. You can also add an org statement to force DAT variables to be long aligned.
Edit: I should add the par parameter ignores the last two bits of the value passed which can cause problems when using byte or word sized variables.
My current guess as to what is causing the problem is there is a call to a variable's address which is moving when I add to/change the program. There are only a handful of variable I can check without changing the program. When the program changes, my guess is the problematic address is also get changed, so I can't always see when EEPROM addresses are being overwritten. After a restart, this could seriously compromise my software. I've checked all the obvious EEPROM writes I have declared, but I fear there is a memory overrun somewhere so it's not as simple to spot where the writing is happening.
The software is extremely dependent on variables in RAM lining up with the same addresses in EEPROM, so it's always programmed to EEPROM.
I'm so glad that is over!
Thank you everyone for your help and ideas!