Shop OBEX P1 Docs P2 Docs Learn Events
[SOLVED] Memory Layout around DAT blocks — Parallax Forums

[SOLVED] Memory Layout around DAT blocks

Bobb FwedBobb Fwed Posts: 1,119
edited 2016-11-16 23:57 in Propeller 1
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.

Comments

  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    IIRC the DAT block gets put toward the beginning of the code. Before the code from the first PUB.

    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.
  • ElectrodudeElectrodude Posts: 1,657
    edited 2016-11-15 23:15
    Spin is a dynamically linked language, but no one takes advantage of this - it just makes the compiler simpler. Nearly all pointers in the final compiled image are relative to something else. Spin methods and objects are looked up in a table on every call. The part of this table that belongs to the top object goes at the beginning of hub ram, right after the 16-byte boot header.

    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.
  • EDIT: Details about the Spin object format can be found at http://forums.parallax.com/discussion/download/115824/Propeller%20Spin%20Architecture.pdf.
    Interestingly, part way through that document there is a section titled "THIS SECTION MAY NOT BE ENTIRELY CORRECT". It's really unfortunate that there has never been a document released that definitively describes the Spin runtime architecture and instruction set.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2016-11-16 00:34
    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).

    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.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2016-11-16 15:44
    Are you passing a byte memory location with par in a PASM routine?
    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.
  • Duane Degn wrote: »
    Are you passing a byte memory location with par in a PASM routine?
    Nope. I did think of the possibility that there was some long-alignment issue, but the value was already long aligned. If I add 1-3 bytes before the value, the bug is reproducible, but if I add 4 or more, I can't reproduce it.

    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.
  • Does the problem happen if you always program EEPROM and not just RAM?
  • Does the problem happen if you always program EEPROM and not just RAM?

    The software is extremely dependent on variables in RAM lining up with the same addresses in EEPROM, so it's always programmed to EEPROM.
  • An EEPROM is organized into multiple pages. When you write several bytes to an EEPROM the address will wrap back to the beginning of the page after you write the last byte of a page. Are you accounting for this? Could this be the problem?
  • Dave Hein wrote: »
    An EEPROM is organized into multiple pages. When you write several bytes to an EEPROM the address will wrap back to the beginning of the page after you write the last byte of a page. Are you accounting for this? Could this be the problem?
    I figured this out about 30 minutes ago! I knew about the pages, and had accounted for it in every place except one. I was writing a 6 byte array to its own address in the EEPROM. If the address of the array happened to land less than 6 bytes before the end of a page, it overwrote some of the EEPROM elsewhere. This write only happens the very first time the software boots up, but because it was affecting variable space it only showed itself after a reboot. And since it is relatively unlikely that the data would line up just so, I didn't see the problem often. Now that I know what is happening, I can account for some other problems we've had in the past that seemed to mysteriously disappear when a line or two of seemingly unrelated code was changed.

    I'm so glad that is over!
    Thank you everyone for your help and ideas!
Sign In or Register to comment.