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
  • ok, let me clarify:
    Idata before the end of data, not necessarily before 0x80 reduces the amount of data space available.

    Obviously if data is only a few bytes, this makes no difference; however since I am hunting for data space, if this bit of idata were at the end of data it would allow me to increase the use of data by that amount.

    Can I trick the linker (possibly by defining the data in a separate module) to locate all IDATA at the end OF DATA.

    Hope this makes it clear

    Erik

Reply
  • ok, let me clarify:
    Idata before the end of data, not necessarily before 0x80 reduces the amount of data space available.

    Obviously if data is only a few bytes, this makes no difference; however since I am hunting for data space, if this bit of idata were at the end of data it would allow me to increase the use of data by that amount.

    Can I trick the linker (possibly by defining the data in a separate module) to locate all IDATA at the end OF DATA.

    Hope this makes it clear

    Erik

Children
  • DATA    0018H     0003H     UNIT        _DATA_GROUP_
    IDATA   001BH     0005H     UNIT         ?ID?AVMAIN
    BIT     0020H.0   0001H.2   UNIT         ?BI?AVMAIN
    

    We're talking about the 5-byte gap between the end of "_DATA_GROUP_" and the start of the bit-addressable memory. If there's no data segment that can fit into that 5-byte area, the linker might well skip over it entirely.

    Page 260 of the Assembler/Utilities manual says:

    Locating Segments
    After the linker/locator combines partial segments it must determine a physical
    address for them. The linker/locator processes each memory class separately.
    Refer to "Memory Classes and Memory Layout" on page 27 for a discussion of
    the different memory class and the physical address ranges.
    After the linker/locator combines partial segments, it must determine a physical
    address for them. The linker/locator places different segments in each of these
    memory areas. The memory is allocated in the following order:
    1. Register Banks and segments with an absolute address.
    2. Segments specified in Lx51 segment allocation controls.
    3. Segments with the relocation type BITADDRESSABLE and other BIT
    segments.
    4. All other segments with the memory class DATA.
    5. Segments with the memory class IDATA, EDATA and NCONST.
    6. Segments with the memory class XDATA.
    7. Segments with the memory class CODE and the relocation type INBLOCK.
    8. Other Segments with the memory class CODE and CONST.
    9. Segments with the memory classes ECODE, HCONST, and HDATA.


    which seems to imply that the linker has already considered putting data into that area, and decided against it, before moving on and finding an idata segment that would fit. Presumably there's no little data segment it can use. (What's the rest of the map file look like?)

    Perhaps you could try breaking up one of your other data segments into two so that one was a 5-byte chunk, and see what happens then?

  • which seems to imply that the linker has already considered putting data into that area, and decided against it, before moving on and finding an idata segment that would fit.

    Exactly correct.

    Jon

  • 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