diff --git a/CHANGELOG.md b/CHANGELOG.md index 42c6126..c913175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to * `flags` can be specified at map file as well * `size` property at root level to modify the document size * `labels` property can go on the left side as well +* Friendly name field (`name`) for sections at the yaml map file to be used instead of ID ## [0.2.0] - 2023-12-14 diff --git a/README.md b/README.md index 542f0e3..0546dc3 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ an `id`, an `address` and a `size`. While these three are needed, there are other possible attributes that are optional: - `name`: Friendly text name that would be used instead of the `id` -- `type`: Section type, which can be used for different purposes. Possibilities are `section` (default) and `area`. +- `type`: Section type, which can be used for different purposes. Current possibilities are `section` (default) and `area`. The input file should contain the `map` keyword whose value is an array of sections. Below an example of how an input file should look like: @@ -67,7 +67,7 @@ of how an input file should look like: - ... ``` -In order to use this file, invoke Linkerscope and specify the yaml map file as input: +In order to use this file, invoke LinkerScope and specify the yaml map file as input: ```bash ./linkerscope.py -i memory_map.yaml -o memory_map.svg -c config.yaml @@ -78,7 +78,7 @@ In order to use this file, invoke Linkerscope and specify the yaml map file as i For a complex diagram that fully represents the memory map of a given program, handcrafting the memory map can be time-consuming. In the case that the intended diagram is related to a program, the necessary information is already available at the generated GNU Linker map files. -Linkerscope conveniently provides the possibility to parse these files and generate diagram from those. For that, simply +LinkerScope conveniently provides the possibility to parse these files and generate diagram from those. For that, simply specify the `.map` file as an input. ```bash @@ -87,93 +87,45 @@ specify the `.map` file as an input. ### Creating a configuration file -The configuration file is a `.yaml` file containing all the required information to tell LinkerScope what and how to draw the maps. -All information there is optional. +The configuration file is a `.yaml` file containing all the required information to tell LinkerScope what and how to draw the memory map. +All information there is optional, including the file itself. If this information is not provided, the default values will be used. -Normally, a configuration file contains style information, memory areas, and links. +Normally, a configuration file contains **areas**, **links** and **style** information. + +**Areas** provides a list of memory areas to be displayed, with information regarding its position and size on the map, memory range to include or specific drawing style. +Additionally, it can contain a **sections** sub-property where specific sections can be added to modify desired properties + +**Links** provides a simple way of graphically relating same memory addresses across different areas + +**Style** defines the parent drawing style properties that will be used at the document. Additionally, each area can override specific style properties at its style section. +Lastly, sections can override parent (area) style as well ```yaml style: - ... + background: '#99B898' + stroke: 'black' + # ... areas: - area: style: - ... - - address: - lowest: 0x0 - highest: 0x200000000 - - size: - ... + # ... + title: Register Map + range: [0x0, 0x100000000] + sections: + - names: [USART1, USART2] + style: + hide-name: true + # ... - area: - ... + # ... links: - addresses: [ 0x80045d4, ...] - sections: [__malloc_av_, ...] - - -``` -#### Styles - -The style can be defined at map level, where it will be applied to all areas, but also at area or even at section level. -Specifying a style at are level will override the specified configuration for the whole map where it was defined. -Specifying it at section level, it will override style information from map and area. + addresses: [0x80045d4] + sections: [__malloc_av_, [TIM2, TIM3]] -```yaml -style: - # RGB colors or english plain text color names can be used - box_fill_color: '#CCE5FF' - label_color: 'blue' - box_stroke_color: '#3399FF' - box_stroke_width: 2 - link_stroke_width: 2 - link_stroke_color: 'grey' - label_font: 'Helvetica Bold' - label_size: '16px' - label_stroke_width: 0.5px - area_fill_color: 'lightgrey' ``` -- Window: - - `background_color` -- Area background - - `area_background_color` -- Memory section rectangle - - `box_fill_color` - - `box_stroke_color` - - `box_stroke_width` -- Section name, address and size - - `label_color` - - `label_font` - - `label_size` - - `label_stroke_width` -- Link lines between addresses at different maps - - `link_stroke_width` - - `link_stroke_color` - -If the style at specific sections needs to be defined/overridden, it will be specified under `style -> overrides -> sections` property at -area level, by specifying the names of the regions whose properties want to be overridden, followed by the properties to override: -```yaml -- area: - ... - address: - ... - style: - # Area style definition - link_stroke_color: 'grey' - link_stroke_width: 1 - section_stroke_width: 0 - section_fill_color: 'blue' - # Area style overrides for specified sections - overrrides: - - sections: [ ROM Table, Peripheral, External RAM ] - section_fill_color: '#99B898' - - sections: [ External PPB ] - section_fill_color: '#FECEA8' -``` #### Areas The diagram can have one or multiple areas. When multiple areas are declared, @@ -283,7 +235,7 @@ areas: flags: break ``` -##### `grows-up` / `grows-down` +##### Growths These flags specify the section as growing section, for instance, if the section is meant to grow into one direction, such as the stack. When flagging a section with `grows-down`, an arrow pointing downwards will be appended to the bottom of the section indicating that the section is growing into that direction: @@ -326,9 +278,56 @@ links: ``` +#### Styles + +The style can be defined at document level, where it will be applied to all areas, but also at area or even at section level. +Specifying a style at area level will override the specified properties for the whole area where it was defined. +Specifying it at section level, it will override style only for the specified section or group of sections. + +```yaml +style: + # This is a style defined at document level + text-fill: 'lightgrey' + background: 'black' + stroke: '#99B898' + stroke-width: 1 + font-type: 'Helvetica' + +areas: +- area: + title: 'Internal Memory' + pos: [30, 50] + style: + # This is a style defined at area level, which will override fill property only applied at Main Memory area + fill: 'blue' + sections: + - names: [ SRAM, Flash ] + style: + # This is a style defined at section level, and will be applied only to SRAM and Flash sections + fill: 'green' + hide-address: true +- area: + title: 'External Memory' + # ... +``` + +Below a list of style properties with general use and specific for sections: +##### General + - `background`, `fill`, `font-size`, `font-type`, `opacity`, `size`, `stroke`, `stroke_dasharray`, `stroke-width`, `text-stroke`,`text-fill`,`text-stroke-width`, `weigth` + +##### Section properties: + - `break-type`: specify memory break type. See [`break`](#break) section + - `break-size`: specify memory break size in pixels. See [`break`](#break) section + - `growth-arrow-size`: size of the direction growth arrow. See [`Growths`](#growths) section + - `growth-arrow-fill`: color for the direction growth arrow. See [`Growths`](#growths) section + - `growth-arrow-stroke`: stroke color for the direction growth arrow. See [`Growths`](#growths) section + - `hide-size`: hides the size label of a section + - `hide-name`: hides the name label of a section + - `hide-address`: hides the address label of a section + #### Other properties -##### Document size +_Document size_ The generated SVG document has a fixed size. If you want to adjust it, use the `size` property at root level to pass desired document width and height in pixels. diff --git a/examples/link_example_config.yaml b/examples/link_example_config.yaml index ab46946..d1378b1 100755 --- a/examples/link_example_config.yaml +++ b/examples/link_example_config.yaml @@ -15,7 +15,7 @@ style: stroke-width: 1 text-stroke: 'black' text-stroke-width: 0 - font_type: 'Helvetica' + font-type: 'Helvetica' areas: - area: diff --git a/examples/link_example_map.svg b/examples/link_example_map.svg index 04212b8..79caa9f 100644 --- a/examples/link_example_map.svg +++ b/examples/link_example_map.svg @@ -1,2 +1,2 @@ -Full Memory MapSRAM AreaPeripheralExternal RAMExternal DeviceAddress Link ExampleTPIU0xe8040000ETM0xe8041000External PPB0xe8042000ROM Table0xe8043000Sections Link ExampleBit0x40100000Bit band alias0x42000000 \ No newline at end of file +Full Memory MapSRAM AreaPeripheralExternal RAMExternal DeviceAddress Link ExampleTPIU0xe8040000ETM0xe8041000External PPB0xe8042000ROM Table0xe8043000Sections Link ExampleBit0x40100000Bit band alias0x42000000 \ No newline at end of file diff --git a/examples/stm32f103_config.yaml b/examples/stm32f103_config.yaml new file mode 100644 index 0000000..a186454 --- /dev/null +++ b/examples/stm32f103_config.yaml @@ -0,0 +1,58 @@ +size: [800,900] +variables: + graphite: &graphite '#2A363B' + pastel_green: &pastel_green '#99B898' + pastel_yellow: &pastel_yellow '#FECEA8' + pastel_orange: &pastel_orange '#FF847C' + pastel_red: &pastel_red '#E84A5F' + +style: + text-fill: 'lightgrey' + break-size: 60 + break-type: '~' + growth-arrow-size: 2 + growth-arrow-fill: 'white' + growth-arrow-stroke: 'black' + background: *graphite + fill: '#99B898' + + stroke: *graphite + stroke-width: 1 + text-stroke: 'black' + text-stroke-width: 0 + font_type: 'Helvetica' + +areas: +# total area area +- area: + range: [0x0, 0x100000000] + size: [200, 700] + style: + fill: *pastel_green + hide-size: true + sections: + - names: [none] + style: + hide-name: true + fill: grey + +- area: + range: [0x40000000, 0x40030000] + pos: [500] + size: [200, 700] + style: + fill: *pastel_green + background: grey + hide-size: true + sections: + - names: [none] + style: + hide-name: true + fill: grey + +links: + style: + fill: grey + sections: [[TIM2, CRC]] + + diff --git a/examples/stm32f103_map.yaml b/examples/stm32f103_map.yaml new file mode 100644 index 0000000..469f8c2 --- /dev/null +++ b/examples/stm32f103_map.yaml @@ -0,0 +1,186 @@ +map: + - id: none + address: 0x00000000 + size: 0x20000000 + type: area + - id: none + address: 0x20000000 + size: 0x20000000 + type: area + - id: none + address: 0x40000000 + size: 0x20000000 + type: area + - id: none + address: 0x60000000 + size: 0x20000000 + type: area + - id: none + address: 0x80000000 + size: 0x20000000 + type: area + - id: none + address: 0xA0000000 + size: 0x20000000 + type: area + - id: none + address: 0xC0000000 + size: 0x20000000 + type: area + + + + - id: none + address: 0xE0100000 + size: 0x0FE00000 + type: area + + - id: SRAM + address: 0x20000000 + size: 0x08000000 + type: area + + - id: Peripherals + address: 0x40000000 + size: 0x08000000 + type: area + + - id: M3 Cortex Internal Peripherals + address: 0xE0000000 + size: 0x01000000 + type: area + + - id: TIM2 + address: 0x40000000 + size: 0x00000400 + type: area + - id: TIM3 + address: 0x40000400 + size: 0x00000400 + type: area + - id: TIM4 + address: 0x40000800 + size: 0x00000400 + type: area + - id: RTC + address: 0x40002800 + size: 0x00000400 + type: area + - id: WWDG + address: 0x40002C00 + size: 0x00000400 + type: area + - id: IWDG + address: 0x40003000 + size: 0x00000400 + type: area + - id: SPI2 + address: 0x40003800 + size: 0x00000400 + type: area + - id: USART2 + address: 0x40004400 + size: 0x00000400 + type: area + - id: USART3 + address: 0x40004800 + size: 0x00000400 + type: area + - id: I2C1 + address: 0x40005400 + size: 0x00000400 + type: area + - id: I2C2 + address: 0x40005800 + size: 0x00000400 + type: area + - id: USB Registers + address: 0x40005C00 + size: 0x00000400 + type: area + - id: USB/CAN SRAM + address: 0x40006000 + size: 0x00000400 + type: area + - id: BXCAN + address: 0x40006400 + size: 0x00000400 + type: area + - id: BKP + address: 0x40006C00 + size: 0x00000400 + type: area + - id: POWER + address: 0x40007000 + size: 0x00000400 + type: area + - id: AFIO + address: 0x40010000 + size: 0x00000400 + type: area + - id: EXTI + address: 0x40010400 + size: 0x00000400 + type: area + - id: PORT A + address: 0x40010800 + size: 0x00000400 + type: area + - id: PORT B + address: 0x40010C00 + size: 0x00000400 + type: area + - id: PORT C + address: 0x40011000 + size: 0x00000400 + type: area + - id: PORT D + address: 0x40011400 + size: 0x00000400 + type: area + - id: PORT E + address: 0x40011800 + size: 0x00000400 + type: area + - id: ADC1 + address: 0x40012400 + size: 0x00000400 + type: area + - id: ADC2 + address: 0x40012800 + size: 0x00000400 + type: area + - id: TIM1 + address: 0x40012C00 + size: 0x00000400 + type: area + - id: SPI1 + address: 0x40013000 + size: 0x00000400 + type: area + - id: + address: 0x40010000 + size: 0x00000400 + type: area + - id: USART1 + address: 0x40013800 + size: 0x00000400 + type: area + - id: DMA + address: 0x40020000 + size: 0x00000400 + type: area + - id: RCC + address: 0x40021000 + size: 0x00000400 + type: area + - id: Flash Interface + address: 0x40022000 + size: 0x00000400 + type: area + - id: CRC + address: 0x40023000 + size: 0x00000400 + type: area + + diff --git a/map_drawer.py b/map_drawer.py index e39b80e..609f9ec 100755 --- a/map_drawer.py +++ b/map_drawer.py @@ -427,7 +427,8 @@ def _make_text(self, ) def _make_name(self, section): - return self._make_text(section.id, + name = section.name if section.name is not None else section.id + return self._make_text(name, (section.name_label_pos_x,section.name_label_pos_y), style=section.style, anchor='middle', diff --git a/map_file_loader.py b/map_file_loader.py index d0988c8..fe5ccf2 100644 --- a/map_file_loader.py +++ b/map_file_loader.py @@ -37,9 +37,11 @@ def parse_yaml(filename): y = yaml.safe_load(file) for element in y['map']: + print(element) sections.append(Section(address=element['address'], size=element['size'], id=element['id'], + name=element.get('name'), parent=element.get('parent', 'none'), _type=element.get('type', 'area'), flags=element.get('flags', '') diff --git a/map_parser.py b/map_parser.py index 0750835..162325c 100644 --- a/map_parser.py +++ b/map_parser.py @@ -9,8 +9,8 @@ class MapParser: Parse a linker map file and convert it to a yaml file for further processing """ def __init__(self, input_filename, output_filename): - self.areas = [] self.sections = [] + self.subsections = [] self.input_filename = input_filename self.output_filename = output_filename @@ -26,22 +26,23 @@ def parse(self): prev_line = line my_dict = {'map': []} - for area in self.areas: + for section in self.sections: my_dict['map'].append({ 'type': 'area', - 'address': area.address, - 'size': area.size, - 'name': area.name, + 'address': section.address, + 'size': section.size, + 'id': section.id, + 'flags': section.flags }) - for section in self.sections: + for subsection in self.subsections: my_dict['map'].append({ 'type': 'section', - 'parent': section.filter_parent, - 'address': section.address, - 'size': section.size, - 'name': section.id, - 'flags': section.flags + 'parent': subsection.parent, + 'address': subsection.address, + 'size': subsection.size, + 'id': subsection.id, + 'flags': subsection.flags }) with open(self.output_filename, 'w', encoding='utf8') as file: @@ -55,13 +56,13 @@ def process_areas(self, line): result = p.search(line) if result is not None: - self.areas.append(Section(parent=None, - id=result.group(1), - address=int(result.group(2), 0), - size=int(result.group(3), 0), - _type='area' - ) - ) + self.sections.append(Section(parent=None, + id=result.group(1), + address=int(result.group(2), 0), + size=int(result.group(3), 0), + _type='area' + ) + ) def process_sections(self, line): pattern = r'\s(.[^.]+).([^. \n]+)[\n\r]\s+(0x[0-9a-fA-F]{16})\s+' \ @@ -71,10 +72,10 @@ def process_sections(self, line): result = p.search(line) if result is not None: - self.sections.append(Section(parent=result.group(1), - id=result.group(2), - address=int(result.group(3), 0), - size=int(result.group(4), 0), - _type='section' - ) - ) + self.subsections.append(Section(parent=result.group(1), + id=result.group(2), + address=int(result.group(3), 0), + size=int(result.group(4), 0), + _type='section' + ) + ) diff --git a/section.py b/section.py index 74c60be..14061ec 100755 --- a/section.py +++ b/section.py @@ -16,12 +16,13 @@ class Section: label_offset: int = 10 style: Style - def __init__(self, size, address, id, _type, parent, flags=[]): + def __init__(self, size, address, id, _type, parent, flags=[], name=None): self.type = _type self.parent = parent self.size = size self.address = address self.id = id + self.name = name self.size_y = 0 self.size_x = 0 self.style = Style() diff --git a/style.py b/style.py index 32c685e..2e62fe5 100644 --- a/style.py +++ b/style.py @@ -33,7 +33,7 @@ class Style: def __init__(self, style=None): if style is not None: for key, value in style.items(): - setattr(self, key.replace('-','_'), style.get(key, value)) + setattr(self, key.replace('-', '_'), style.get(key, value)) def override_properties_from(self, style): """ @@ -66,7 +66,6 @@ def get_default(): default_style.growth_arrow_size = 1 default_style.background = 'white' - default_style.fill = '#CCE5FF' default_style.stroke = 'black' default_style.stroke_width = 1 default_style.size = 2