cancel
Showing results for 
Search instead for 
Did you mean: 

Reading mapfiles - a tool for you

papadeltasierra
Associate III

I have seen a number of questions about reading the stm8s mapfiles and I was also someone who struggled so the attached tool might be helpful (and do let me know of any errors!).

The key elements are:

- There are some elements that are stored in ROM (", from" segments) and also then copied to RAM (", initialized") so they require space in both ROM and RAM

- Other segments require space in either ROM or RAM

- There can be (apparently) wasted space in the RAM allocation.

Perhaps not the best Python code I've every written but hopefully it helps folk.

"""Small script to add up resource usage from map file."""
import sys
import re

SEGMENTS = r"segments"
RGX_SEGMENTS = re.compile(
    r".*?Segments.*?\-+(?P<" + SEGMENTS + r">.*?)\-+.*?Modules.*",
    re.DOTALL | re.MULTILINE)
START = r"start"
END = r"end"
LENGTH = r"length"
NAME = r"NAME"
RGX_SEGDATA = re.compile(
    r"start\s+(?P<" + START + r">[0-9a-f]{8})\s+end\s+(?P<" + END + r">[0-9a-f]{8})\s+length\s+(?P<" +
    LENGTH +
    r">\d+)\s+segment\s+(?P<" + NAME + r">.+)",
    re.IGNORECASE)
with open(sys.argv[1], "r") as mapfile:
    mapdata = mapfile.read()

ROM_SEGMENTS = [".text", ".const", ".bsct", ".init"]
RAM_SEGMENTS = [".ubsct", ".bit", ".data", ".bsct", ".bss", ".share"]
EEPROM_SEGMENTS = [".eeprom"]
HOST_SEGMENTS = [".debug", ".info."]

match = RGX_SEGMENTS.search(mapdata)
assert match, "Unexpected mapfile format"
segments = match.group(SEGMENTS)
segments = segments.strip()
segarray = segments.split("\n")
segmap = {}
for segment in segarray:
    match = RGX_SEGDATA.match(segment)
    assert match, "Unexpected segment data format: %s" % segment
    segmap[match.group(NAME)] = {
        START: int(match.group(START), 16),
        END: int(match.group(END), 16),
        LENGTH: int(match.group(LENGTH))
    }

# Add up the reosurces, ignoring resources that are not present.
rom = 0
romMax = 0
romMin = 0xFFFFFFFF
ram = 0
ramMax = 0
ramMin = 0xFFFFFFFF
eeprom = 0
eepromMax = 0
eepromMin = 0xFFFFFFFF

for key, segValue in segmap.items():
    if key.endswith("initialized"):
        ram += segValue[LENGTH]
        ramMin = min(ramMin, segValue[START])
        ramMax = max(ramMax, segValue[END])
    elif key.endswith("from"):
        rom += segValue[LENGTH]
        romMin = min(romMin, segValue[START])
        romMax = max(romMax, segValue[END])
    elif key in ROM_SEGMENTS:
        rom += segValue[LENGTH]
        romMin = min(romMin, segValue[START])
        romMax = max(romMax, segValue[END])
    elif key in RAM_SEGMENTS:
        ram += segValue[LENGTH]
        ramMin = min(ramMin, segValue[START])
        ramMax = max(ramMax, segValue[END])
    elif key in EEPROM_SEGMENTS:
        eeprom += segValue[LENGTH]
        eepromMin = min(eepromMin, segValue[START])
        eepromMax = max(eepromMax, segValue[END])
    elif key not in HOST_SEGMENTS:
        print("Unexpected segment: %s: %s" % (key, segValue[LENGTH]))

print("Resource: start     end      length  waste")
print("ROM:      %8.8X, %8.8X, %5d, %5d" % (romMin, romMax, rom, (romMax - romMin - rom)))
print("RAM:      %8.8X, %8.8X, %5d, %5d" % (ramMin, ramMax, ram, (ramMax - ramMin - ram)))
print("EEPROM:   %8.8X, %8.8X, %5d, %5d" % (eepromMin, eepromMax, eeprom, (eepromMax - eepromMin - eeprom)))

 

2 REPLIES 2
papadeltasierra
Associate III

One improvement that I could make.  There are a number of segments that appear "twice" because they contain data that is initialized (and therefore stored in ROM) but might change and therefore also has to be copied into RAM.  These are typically identified in the mapfile using labels like this:

.seg, initialized
.seg, from

where the initialized is the RAM and from is the ROM.  But if the segment is not used, it can appear just with the segment name and length 0 and I've currently cheated slight by adding these segments to the RAM list to avoid the program complaining about an unrecognised segment.

A better fix might be a MAYBE_ZERO list of such segments.  The specific test for endswith("initialized") and endswith("from") will catch them when really used and if these tests miss them, then an in MAYBE_ZERO test should check that the length really is zero.

Someone pointed out that segments can be renamed so mapping segments to ROM (flash), RAM, EEPROM is not a sensible approach.  So I think a better approach is to look at the address start/end and map those based on the standard stm8 address layout so...

- 0x00000000 to 0x0000007f, tiny (short address) RAM

- 0x00000080 to 0x00003fff, (near and far address) RAM

- 0x00004000 to 0x00007fff, EEPROM

- 0x00008000 upwards, ROM (flash).

Also note the tiny address space.  In my original, this gave rise to some "wasted" RAM space because the variables were "tiny" then there was a gap to some "in-RAM" functions that had to be "near".