This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Why IDATA in MAIN

I am trying to find the best places to save some DATA storage to use it in a more speed sensitive area.
Looking at the map, I see the following:

            TYPE    BASE      LENGTH    RELOCATION   SEGMENT NAME
            -----------------------------------------------------

            * * * * * * *   D A T A   M E M O R Y   * * * * * * *
            REG     0000H     0008H     ABSOLUTE     "REG BANK 0"
            REG     0008H     0008H     ABSOLUTE     "REG BANK 1"
            REG     0010H     0008H     ABSOLUTE     "REG BANK 2"
            DATA    0018H     0003H     UNIT         _DATA_GROUP_
            IDATA   001BH     0005H     UNIT         ?ID?AVMAIN
            BIT     0020H.0   0001H.2   UNIT         ?BI?AVMAIN
Main has NO idata storage and one BIT.
I verified the idata, there is no @r in the assembler source.
what is the IDATA attributed to main?

Erik

Parents Reply Children
  • In other words: global data is atored by the linker in one chunk that will not be split although that should not be a problem.
    correct?

    Erik


  • I think the C compiler generates one data segment per source file for the global data (if you have data defined, of course). Look for segments with names like ?DT?FILENAME. There's not one single segment for all global data. Take a look at Chapter 9 of the Assembler/Utilities manual. (I don't know why the linker has been banished to a mere "utility" chapter, as it's pretty important. But the poor thing doesn't get its own manual, alas.)

    A linker can't break segments into pieces. It doesn't know, for example, that your 10-byte segment is really 10 independent unsigned chars, and not a char array[10], so it can't be sure it can safely lop the segment in half and put the two halves in different places. The compiler would have to generate different segments for the linker to independently locate.

    If you examine the map file, I suspect you'll find that you don't have any ?DT?FILENAME segments that are five bytes or smaller. You've got three register banks. Then there's _DATA_GROUP_, which is assigned to 18H, three bytes long (through 1AH). At this point, you have a five-byte hole at 1BH until 20H, where the bit-addressable memory starts. If there aren't any more data segments that are five bytes or smaller, then nothing can fit into that hole, and the linker would have to assign those segments higher addresses.

    If you have (hypothetically) an 8-byte segment (call it DT8), then you could argue that perhaps the 3-byte _DATA_GROUP_ should be moved, and DT located at 18H instead. That would leave you with three bytes of data you can't place, instead of an 8 byte segment you can't place and a five-byte hole. Less annoying, maybe, but it doesn't really solve the problem.

    Can you come up with a manual arrangement of your segments that actually fits in data space that the linker couldn't find? (I assume you only posted a fragment of your map file above, or you wouldn't be worried about running out of space.)

    I think that what you want is a compiler pragma to let you break up the data segments manually, something like:

    #pragma segment ERIK1
    char data array1[5];
    #pragma segment ERIK2
    char data array2[3];
    #pragma segment default
    

    I don't think there is such a pragma in C51. Makes a nice feature request, though.

    You can get the same effect by creating new .c files to hold the variables, one for each segment you need. A bit of a kludge, but if makes your program fit, perhaps it's worth it. If you had the above declarations in erik.c, you might make

    erik.c:
    extern U8 data array1[5];  // was local decl
    extern U8 data array2[3];  // was local decl
    
    erik_seg1.c:
    U8 data array1[5];
    
    erik_seg1.c:
    U8 data array2[3];
    

    Then you should get two segments, ?DT?ERIK_SEG1 (5 bytes) and ?DT?ERIK_SEG2 (3 bytes), instead of just ?DT?ERIK (8 bytes).

    If you're programming in assembler, then you can assign your data to segments on a whim with the "SEGMENT DATA" directive.

  • Does anyone know if there is a way to get the compiler to create separate segments for variables in a single source file as Drew describes? I usually wind up forcing variables into the space below 0x20 using the _at_ keyword - but suffer from the infamous 'can't initialise variables declared with _at_' problem.

    Stefan