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

Unknown information in *.M51 file

Dear All:

While I am studying *.M51 file, I discovered serveral unknown descriptions with which I need your help.

Section:

LINK MAP OF MODULE: .\obj\moonplus (MAIN)
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"
REG 0018H 0008H ABSOLUTE "REG BANK 3"
BIT 0020H.0 0002H.2 UNIT _BIT_GROUP_
BIT 0022H.2 0000H.7 UNIT ?BI?MAIN
BIT 0023H.1 0000H.6 UNIT ?BI?L1_5B
BIT 0023H.7 0000H.6 UNIT ?BI?DOSFAT
BIT 0024H.5 0000H.5 UNIT ?BI?SONY_LENS
BIT 0025H.2 0000H.3 UNIT ?BI?UIFLOW
BIT 0025H.5 0000H.3 UNIT ?BI?IQDEBUG
BIT 0026H.0 0000H.2 UNIT ?BI?MCU
BIT 0026H.2 0000H.2 UNIT ?BI?SKYLAR_SHIT
BIT 0026H.4 0000H.2 UNIT ?BI?BUBU_3B
BIT 0026H.6 0000H.1 UNIT ?BI?BULKOUT
BIT 0026H.7 0000H.1 UNIT ?BI?L1_PREVIEW
BIT 0027H.0 0000H.1 UNIT ?BI?DOSRW
BIT 0027H.1 0000H.1 UNIT ?BI?MEMORY_RW?MCU
BIT 0027H.2 0000H.1 UNIT ?BI?GOTOCURGAIN?BUBU_3B
0027H.3 0000H.5 *** GAP ***
DATA 0028H 0018H UNIT _DATA_GROUP_
DATA 0040H 0009H UNIT ?DT?L1_ISP
DATA 0049H 0002H UNIT ?DT?DOSFAT
DATA 004BH 0002H UNIT ?DT?SMC_READREDUNDATA2SRAM?SMCHW533
DATA 004DH 0002H UNIT ?DT?BUBU_3B
DATA 004FH 0001H UNIT ?DT?SMCCORE
DATA 0050H 0004H ABSOLUTE
DATA 0054H 0004H ABSOLUTE
DATA 0058H 0004H ABSOLUTE
DATA 005CH 0002H ABSOLUTE
DATA 005EH 0008H UNIT ?DT?MAIN
DATA 0066H 0001H UNIT ?DT?IQDEBUG
IDATA 0067H 000CH UNIT ?ID?DOSRW
IDATA 0073H 0006H UNIT ?ID?CTLSETUP
IDATA 0079H 0004H UNIT ?ID?AVILIB
IDATA 007DH 0004H UNIT ?ID?DOSFAT
===================================================

In the "TYPE" column, what are the difference between "REG", "BIT", "DATA" and "IDATA" ?

In the "RELOCATION" column, what are the meanings of "ABSOLUTE" and "UNIT" ?

How do I control "GAP" segment?

Any suggestion will be highly appreciated.

Best,
Yuncheng Lin (Eric)

  • It is fairly straightforward, although for the most part this is something that you really should not need to worry about.

    The TYPE column refers to the memory type, where BIT is bit addressable memory, DATA is internal directly addressable memory and IDATA is internal indirectly addressable memory. REG is a special case being the internal directly addressable memory that is reserved for the register banks. You will find out more all this in the Keil documentation and appropriate data sheets.

    Sections that are ABSOLUTE have a predetermined fixed place in memory and cannot be moved by the linker. Sections that are not ABSOULTE will be given a memory location by the linker/locator.

    A GAP will occur where the linker/locator cannot find anything to place in a range of memory locations. Your program has used a certain abount of bit addressable memory, but these bits must be fitted into a whole number of bytes ending in byte 0x27 of directly addressable RAM. This leaves a few unused bits left over. Your directly addressable RAM use starts are byte 0x28.

  • Dear Graham:

    Thank you for those patient explanations. The reason why I concerned about those information is that I found a warning message as follows:

    Warning: L15 Multiple Call to Segment
    Segment: ?PR?PRINTF?PRINTF
    Caller1: ?PR?INTR_INT0?INTR
    Caller2: ?C_C51STARTVP

    I just have no idea why this happened.

    Yuncheng Lin

  • Warning: L15 Multiple Call to Segment
    Segment: ?PR?PRINTF?PRINTF
    Caller1: ?PR?INTR_INT0?INTR
    Caller2: ?C_C51STARTVP
    
    The L15 Multiple Call to Segment is a problem quite unrelated to your earlier question.

    The root of this problem is that printf() is being called from two different threads of execution; this is not allowed because printf() is not re-enterant.

    Caller2 (?C_C51STARTVP) is the main thread of execution which begins when the startup code makes a jump to the main() function.

    Caller1 (?PR?INTR_INT0?INTR) looks like it must be an interrupt service routine (ISR). Potentially, execution of this ISR can start at any time.

    Therefore, it is possible that printf() is being executed as a result of a call from the main thread and that an interrupt may occur part way through the execution of printf(). This interrupt then itself calls printf(). i.e. the CPU has re-entered printf(). printf() was not designed to cope with this and it will fail.

    A significant proportion of the C51 library functions are non re-enterant. At first, this might seem most inconvenient; but in fact it is something of a blessing in disguise. The reason is simply that, in general, calling these non re-enterant library functions from ISRs suggests a poor top-level design.

    To avoid this problem you will have to reconsider your top-level design.

  • Caller1 (?PR?INTR_INT0?INTR) looks like it must be an interrupt service routine (ISR). Potentially, execution of this ISR can start at any time.

    Yes, (?PR?INTR_INT0?INTR) itself is an interrupt service, does it mean that I shouldn't touch any non-re-entreed function in interrupt service? But how do I know if a function is re-entreed or not? Can I write some re-entreed function myself? How does the Linker know that (?PR?INTR_INT0?INTR) is my interrupt service? So many questions, sorry to bother you. :)

    Thanks.

    Yuncheng

  • does it mean that I shouldn't touch any non-re-entreed function in interrupt service?

    Yes. A non-reentrant function, by definition, maintains some sort of internal state. If you call it while some other context was halfway through the call, this internal state will be messed up when you return from the interrupt call.

    But how do I know if a function is re-entreed or not?

    The library reference manual tells you whether or not a function is reentrant for each function.

    Can I write some re-entreed function myself?

    Yes. Either make sure that your function does not have this sort of internal state (no static locals, no parameters that spill over onto the stack, no temporary stack needed), or, to be certain, declare the function reentrant so that the compiler will generate reentrant code, using an external stack as necessary.

    By default, functions will not be reentrant with C51. Note that this behavior is a departure from standard C.

    How does the Linker know that (?PR?INTR_INT0?INTR) is my interrupt service?

    Presumably, you declared it with the interrupt keyword? Any function that is not called will also serve as the root of its own call tree.