powertrain-build 1.13.1__py3-none-any.whl → 1.13.3.dev3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- powertrain_build/__init__.py +40 -40
- powertrain_build/__main__.py +6 -6
- powertrain_build/a2l.py +582 -582
- powertrain_build/a2l_merge.py +650 -650
- powertrain_build/a2l_templates.py +717 -717
- powertrain_build/build.py +985 -985
- powertrain_build/build_defs.py +309 -309
- powertrain_build/build_proj_config.py +690 -690
- powertrain_build/check_interface.py +575 -575
- powertrain_build/cli.py +141 -141
- powertrain_build/config.py +542 -542
- powertrain_build/core.py +395 -395
- powertrain_build/core_dummy.py +343 -343
- powertrain_build/create_conversion_table.py +73 -73
- powertrain_build/dids.py +916 -916
- powertrain_build/dummy.py +157 -157
- powertrain_build/dummy_spm.py +252 -252
- powertrain_build/environmentcheck.py +52 -52
- powertrain_build/ext_dbg.py +255 -255
- powertrain_build/ext_var.py +327 -327
- powertrain_build/feature_configs.py +301 -301
- powertrain_build/gen_allsysteminfo.py +227 -227
- powertrain_build/gen_label_split.py +449 -449
- powertrain_build/handcode_replacer.py +124 -124
- powertrain_build/html_report.py +133 -133
- powertrain_build/interface/__init__.py +4 -4
- powertrain_build/interface/application.py +511 -511
- powertrain_build/interface/base.py +500 -500
- powertrain_build/interface/csp_api.py +490 -490
- powertrain_build/interface/device_proxy.py +677 -677
- powertrain_build/interface/ems.py +67 -67
- powertrain_build/interface/export_global_vars.py +121 -121
- powertrain_build/interface/generate_adapters.py +132 -132
- powertrain_build/interface/generate_hi_interface.py +87 -87
- powertrain_build/interface/generate_service.py +69 -69
- powertrain_build/interface/generate_wrappers.py +147 -147
- powertrain_build/interface/generation_utils.py +142 -142
- powertrain_build/interface/hal.py +194 -194
- powertrain_build/interface/model_yaml_verification.py +348 -348
- powertrain_build/interface/service.py +296 -296
- powertrain_build/interface/simulink.py +249 -249
- powertrain_build/interface/update_call_sources.py +180 -180
- powertrain_build/interface/update_model_yaml.py +186 -186
- powertrain_build/interface/zone_controller.py +362 -362
- powertrain_build/lib/__init__.py +4 -4
- powertrain_build/lib/helper_functions.py +127 -127
- powertrain_build/lib/logger.py +55 -55
- powertrain_build/matlab_scripts/CodeGen/BuildAutomationPyBuild.m +78 -78
- powertrain_build/matlab_scripts/CodeGen/Generate_A2L.m +154 -154
- powertrain_build/matlab_scripts/CodeGen/generateTLUnit.m +239 -239
- powertrain_build/matlab_scripts/CodeGen/getAsilClassification.m +28 -28
- powertrain_build/matlab_scripts/CodeGen/modelConfiguredForTL.m +28 -28
- powertrain_build/matlab_scripts/CodeGen/moveDefOutports.m +88 -88
- powertrain_build/matlab_scripts/CodeGen/parseCalMeasData.m +410 -410
- powertrain_build/matlab_scripts/CodeGen/parseCoreIdentifiers.m +139 -139
- powertrain_build/matlab_scripts/CodeGen/parseDIDs.m +141 -141
- powertrain_build/matlab_scripts/CodeGen/parseInPorts.m +106 -106
- powertrain_build/matlab_scripts/CodeGen/parseIncludeConfigs.m +25 -25
- powertrain_build/matlab_scripts/CodeGen/parseModelInfo.m +38 -38
- powertrain_build/matlab_scripts/CodeGen/parseNVM.m +81 -81
- powertrain_build/matlab_scripts/CodeGen/parseOutPorts.m +120 -120
- powertrain_build/matlab_scripts/CodeGen/parsePreProcBlks.m +23 -23
- powertrain_build/matlab_scripts/CodeGen/struct2JSON.m +128 -128
- powertrain_build/matlab_scripts/CodeGen/updateCodeSwConfig.m +31 -31
- powertrain_build/matlab_scripts/Init_PyBuild.m +91 -91
- powertrain_build/matlab_scripts/__init__.py +2 -2
- powertrain_build/matlab_scripts/helperFunctions/Get_Full_Name.m +46 -46
- powertrain_build/matlab_scripts/helperFunctions/Get_SrcLines.m +12 -12
- powertrain_build/matlab_scripts/helperFunctions/Init_Models.m +78 -78
- powertrain_build/matlab_scripts/helperFunctions/Init_Projects.m +67 -67
- powertrain_build/matlab_scripts/helperFunctions/Read_Units.m +34 -34
- powertrain_build/matlab_scripts/helperFunctions/SetProjectTimeSamples.m +26 -26
- powertrain_build/matlab_scripts/helperFunctions/Strip_Suffix.m +16 -16
- powertrain_build/matlab_scripts/helperFunctions/followLink.m +118 -118
- powertrain_build/matlab_scripts/helperFunctions/getCodeSwitches.m +50 -50
- powertrain_build/matlab_scripts/helperFunctions/getConsumerBlocks.m +30 -30
- powertrain_build/matlab_scripts/helperFunctions/getDefBlock.m +39 -39
- powertrain_build/matlab_scripts/helperFunctions/getDefOutport.m +58 -58
- powertrain_build/matlab_scripts/helperFunctions/getDstBlocks.m +19 -19
- powertrain_build/matlab_scripts/helperFunctions/getDstLines.m +13 -13
- powertrain_build/matlab_scripts/helperFunctions/getInterfaceSignals.m +37 -37
- powertrain_build/matlab_scripts/helperFunctions/getName.m +37 -37
- powertrain_build/matlab_scripts/helperFunctions/getPath.m +6 -6
- powertrain_build/matlab_scripts/helperFunctions/getProperValue.m +21 -21
- powertrain_build/matlab_scripts/helperFunctions/getSrcBlocks.m +19 -19
- powertrain_build/matlab_scripts/helperFunctions/getSrcLines.m +13 -13
- powertrain_build/matlab_scripts/helperFunctions/loadLibraries.m +10 -10
- powertrain_build/matlab_scripts/helperFunctions/loadjson.m +6 -6
- powertrain_build/matlab_scripts/helperFunctions/modifyEnumStructField.m +21 -21
- powertrain_build/matlab_scripts/helperFunctions/removeConfigDuplicates.m +31 -31
- powertrain_build/matlab_scripts/helperFunctions/sortSystemByClass.m +26 -26
- powertrain_build/matlab_scripts/helperFunctions/tl_getfast.m +89 -89
- powertrain_build/matlab_scripts/helperFunctions/topLevelSystem.m +20 -20
- powertrain_build/matlab_scripts/helperFunctions/updateModels.m +131 -131
- powertrain_build/memory_section.py +224 -224
- powertrain_build/nvm_def.py +729 -729
- powertrain_build/problem_logger.py +86 -86
- powertrain_build/pt_matlab.py +430 -430
- powertrain_build/pt_win32.py +144 -144
- powertrain_build/replace_compu_tab_ref.py +105 -105
- powertrain_build/rte_dummy.py +254 -254
- powertrain_build/sched_funcs.py +209 -207
- powertrain_build/signal.py +7 -7
- powertrain_build/signal_if_html_rep.py +221 -221
- powertrain_build/signal_if_html_rep_all.py +302 -302
- powertrain_build/signal_incons_html_rep.py +180 -180
- powertrain_build/signal_incons_html_rep_all.py +366 -366
- powertrain_build/signal_incons_html_rep_base.py +168 -168
- powertrain_build/signal_inconsistency_check.py +641 -641
- powertrain_build/signal_interfaces.py +864 -864
- powertrain_build/templates/Index_SigCheck_All.html +22 -22
- powertrain_build/templates/Index_SigIf_All.html +19 -19
- powertrain_build/types.py +218 -218
- powertrain_build/unit_configs.py +419 -419
- powertrain_build/user_defined_types.py +660 -660
- powertrain_build/versioncheck.py +66 -66
- powertrain_build/wrapper.py +512 -512
- powertrain_build/xlrd_csv.py +87 -87
- powertrain_build/zone_controller/__init__.py +4 -4
- powertrain_build/zone_controller/calibration.py +176 -176
- powertrain_build/zone_controller/composition_yaml.py +880 -878
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/METADATA +100 -100
- powertrain_build-1.13.3.dev3.dist-info/RECORD +130 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/WHEEL +1 -1
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/LICENSE +202 -202
- powertrain_build-1.13.3.dev3.dist-info/pbr.json +1 -0
- powertrain_build-1.13.1.dist-info/RECORD +0 -130
- powertrain_build-1.13.1.dist-info/pbr.json +0 -1
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/entry_points.txt +0 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/AUTHORS +0 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/licenses/NOTICE +0 -0
- {powertrain_build-1.13.1.dist-info → powertrain_build-1.13.3.dev3.dist-info}/top_level.txt +0 -0
powertrain_build/nvm_def.py
CHANGED
|
@@ -1,729 +1,729 @@
|
|
|
1
|
-
# Copyright 2024 Volvo Car Corporation
|
|
2
|
-
# Licensed under Apache 2.0.
|
|
3
|
-
|
|
4
|
-
# -*- coding: utf-8 -*-
|
|
5
|
-
"""Module for handling of NVM definitions and for generation of c&h-files defining the memory layout of the NVM."""
|
|
6
|
-
import re
|
|
7
|
-
import os
|
|
8
|
-
import json
|
|
9
|
-
from copy import deepcopy
|
|
10
|
-
|
|
11
|
-
import powertrain_build.build_defs as bd
|
|
12
|
-
from powertrain_build.types import byte_size, get_bitmask
|
|
13
|
-
from powertrain_build.a2l import A2l
|
|
14
|
-
from powertrain_build.problem_logger import ProblemLogger
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class NVMDef(ProblemLogger):
|
|
18
|
-
"""A class that holds the NVM definitions for the build.
|
|
19
|
-
|
|
20
|
-
Provides methods for generating NVM structs and header files.
|
|
21
|
-
The header files includes defines which reference the
|
|
22
|
-
struct elements as variables.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
class WrongTypeException(Exception):
|
|
26
|
-
"""WrongTypeException."""
|
|
27
|
-
|
|
28
|
-
_allowed_nvm_memory_areas = [
|
|
29
|
-
"NVM_LIST_32",
|
|
30
|
-
"NVM_LIST_16",
|
|
31
|
-
"NVM_LIST_8",
|
|
32
|
-
"NVM_LIST_32_PER",
|
|
33
|
-
"NVM_LIST_16_PER",
|
|
34
|
-
"NVM_LIST_8_PER",
|
|
35
|
-
"NVM_LIST_CRITICAL1",
|
|
36
|
-
"NVM_LIST_CRITICAL2",
|
|
37
|
-
]
|
|
38
|
-
|
|
39
|
-
_nvm_header_footer = "\n#endif /* VCC_NVM_STRUCT_H */\n"
|
|
40
|
-
|
|
41
|
-
def __init__(self, project_config, unit_cfg, nvm_vars):
|
|
42
|
-
"""Constructor.
|
|
43
|
-
|
|
44
|
-
Args:
|
|
45
|
-
project_config (BuildProjConfig): current project configuration
|
|
46
|
-
unit_cfg (UnitConfigs): unit definitions
|
|
47
|
-
nvm_vars (dict): NVM variables from unit configurations (:doc:`UnitConfigs <unit_configs>`)
|
|
48
|
-
|
|
49
|
-
"""
|
|
50
|
-
super().__init__()
|
|
51
|
-
self._project_config = project_config
|
|
52
|
-
self._nvm_vars = nvm_vars
|
|
53
|
-
# get the size of areas and c-file names
|
|
54
|
-
self._nvm_defs = project_config.get_nvm_defs()
|
|
55
|
-
self._nvm_signals = {}
|
|
56
|
-
self._nvm_memory_areas = tuple()
|
|
57
|
-
self._mem_area_elem_size = {}
|
|
58
|
-
self._area_section = {}
|
|
59
|
-
self._mem_area_pragmas = tuple()
|
|
60
|
-
self._nvm_header_head = self._get_nvm_header_head(unit_cfg)
|
|
61
|
-
src_file_dst = self._project_config.get_src_code_dst_dir()
|
|
62
|
-
self._file_name = os.path.join(src_file_dst, self._nvm_defs["fileName"])
|
|
63
|
-
self._predecl_start = bd.PREDECL_START
|
|
64
|
-
self._predecl_end = bd.PREDECL_END
|
|
65
|
-
self.struct_member_prefix = "_"
|
|
66
|
-
|
|
67
|
-
with open(
|
|
68
|
-
os.path.join(project_config.get_root_dir(), self._nvm_defs["baseNvmStructs"]), "r", encoding="utf-8"
|
|
69
|
-
) as nvm_json:
|
|
70
|
-
self.nvm_definitions = json.load(nvm_json)
|
|
71
|
-
for memory_area in self.nvm_definitions:
|
|
72
|
-
self._add_memory_area(memory_area)
|
|
73
|
-
self._order_nvm_per_area()
|
|
74
|
-
for memory_area in self.nvm_definitions:
|
|
75
|
-
memory_index = self._get_nvm_areas_index(memory_area["name"])
|
|
76
|
-
self.info("Updating %s with index %s", memory_area["name"], memory_index)
|
|
77
|
-
self.nvm_definitions[memory_index]["signals"] = self._get_signal_list(memory_area["signals"])
|
|
78
|
-
|
|
79
|
-
@staticmethod
|
|
80
|
-
def _get_nvm_header_head(unit_cfg):
|
|
81
|
-
_nvm_header_head = (
|
|
82
|
-
"/*\n"
|
|
83
|
-
" * vcc_nvm_struct.h - struct for NVM signals\n"
|
|
84
|
-
" */\n\n"
|
|
85
|
-
"#ifndef VCC_NVM_STRUCT_H\n"
|
|
86
|
-
"#define VCC_NVM_STRUCT_H\n\n"
|
|
87
|
-
)
|
|
88
|
-
_nvm_header_head += unit_cfg.base_types_headers
|
|
89
|
-
return _nvm_header_head
|
|
90
|
-
|
|
91
|
-
def _add_memory_area(self, memory_area):
|
|
92
|
-
"""Add non-default areas."""
|
|
93
|
-
if memory_area["name"] not in self._allowed_nvm_memory_areas:
|
|
94
|
-
msg = f"Memory area: {memory_area['name']} not allowed"
|
|
95
|
-
self.critical(msg)
|
|
96
|
-
raise NVMDef.WrongTypeException(msg)
|
|
97
|
-
|
|
98
|
-
self._nvm_memory_areas = (*self._nvm_memory_areas, memory_area["name"])
|
|
99
|
-
self._mem_area_elem_size.update({memory_area["name"]: byte_size(memory_area["default_datatype"])})
|
|
100
|
-
|
|
101
|
-
if memory_area["persistent"]:
|
|
102
|
-
self._area_section.update({memory_area["name"]: "CVC_NVM_P"})
|
|
103
|
-
self._mem_area_pragmas = (*self._mem_area_pragmas, (bd.CVC_NVM_P_START, bd.CVC_NVM_P_END))
|
|
104
|
-
else:
|
|
105
|
-
self._area_section.update({memory_area["name"]: "CVC_NVM"})
|
|
106
|
-
self._mem_area_pragmas = (*self._mem_area_pragmas, (bd.CVC_NVM_START, bd.CVC_NVM_END))
|
|
107
|
-
|
|
108
|
-
def _var_to_area(self, var_info):
|
|
109
|
-
"""Find the NVM area for the variable.
|
|
110
|
-
|
|
111
|
-
Args:
|
|
112
|
-
var_info (dict): a dict with the variable attributes.
|
|
113
|
-
|
|
114
|
-
Returns:
|
|
115
|
-
area (str): a string with the area the variable should be
|
|
116
|
-
defined in.
|
|
117
|
-
|
|
118
|
-
"""
|
|
119
|
-
mtch = re.match(r"\D+(\d+)?", var_info["type"])
|
|
120
|
-
if mtch.group(1) is None:
|
|
121
|
-
size = "8"
|
|
122
|
-
else:
|
|
123
|
-
size = mtch.group(1)
|
|
124
|
-
if var_info["class"] == "CVC_DISP_NVM":
|
|
125
|
-
return "NVM_LIST_" + size
|
|
126
|
-
if var_info["class"] == "CVC_DISP_NVM_P":
|
|
127
|
-
return "NVM_LIST_" + size + "_PER"
|
|
128
|
-
self.critical("%s is not a NVM variable!", var_info["name"])
|
|
129
|
-
return None
|
|
130
|
-
|
|
131
|
-
def _order_nvm_per_area(self):
|
|
132
|
-
"""Order the NVM in the areas, based on the definitions."""
|
|
133
|
-
for var, unit_attrib in self._nvm_vars.items():
|
|
134
|
-
for _, var_attribs in unit_attrib.items():
|
|
135
|
-
area = self._var_to_area(var_attribs)
|
|
136
|
-
self._nvm_signals[var] = var_attribs
|
|
137
|
-
self._nvm_signals[var]["area"] = area
|
|
138
|
-
# only use one units definition
|
|
139
|
-
# TODO:Make a nicer solution #
|
|
140
|
-
break
|
|
141
|
-
|
|
142
|
-
def nvm_area_iterator(self, nvm_area_name):
|
|
143
|
-
"""Get an iterator for NVM 'area'.
|
|
144
|
-
|
|
145
|
-
The iterator yields data_type and and variable name for the
|
|
146
|
-
variables defined in the area.
|
|
147
|
-
|
|
148
|
-
Args:
|
|
149
|
-
nvm_area_name (str): the name of the NVM area
|
|
150
|
-
|
|
151
|
-
Returns:
|
|
152
|
-
tuple: (data_type, variable name, size)
|
|
153
|
-
|
|
154
|
-
"""
|
|
155
|
-
for nvm_signal_name, nvm_attributes in self._nvm_signals.items():
|
|
156
|
-
if nvm_attributes["area"] == nvm_area_name:
|
|
157
|
-
yield nvm_attributes.get("type"), nvm_signal_name, nvm_attributes.get("width", 1)
|
|
158
|
-
|
|
159
|
-
def _a2l_dict(self):
|
|
160
|
-
"""Return a dict defining all parameters for a2l-generation."""
|
|
161
|
-
res = {}
|
|
162
|
-
for var, var_attrib in self._nvm_signals.items():
|
|
163
|
-
variable_name = self._get_struct_and_variable_name(var_attrib["area"])[1]
|
|
164
|
-
res[var] = {
|
|
165
|
-
"var": {"var": var, "type": var_attrib["type"], "cvc_type": "CVC_NVM"},
|
|
166
|
-
"a2l_data": {
|
|
167
|
-
"bitmask": get_bitmask(var_attrib["type"]),
|
|
168
|
-
"description": var_attrib["description"],
|
|
169
|
-
"lsb": var_attrib.get("lsb", 1),
|
|
170
|
-
"max": var_attrib.get("max"),
|
|
171
|
-
"min": var_attrib.get("min"),
|
|
172
|
-
"offset": var_attrib.get("offset"),
|
|
173
|
-
"unit": var_attrib["unit"],
|
|
174
|
-
"symbol": variable_name,
|
|
175
|
-
"symbol_offset": var_attrib.get("struct_off"),
|
|
176
|
-
},
|
|
177
|
-
}
|
|
178
|
-
width = var_attrib.get("width", 1)
|
|
179
|
-
if width:
|
|
180
|
-
if isinstance(width, list):
|
|
181
|
-
res[var]["array"] = width
|
|
182
|
-
elif int(width) > 1:
|
|
183
|
-
res[var]["array"] = [width]
|
|
184
|
-
return {"vars": res, "function": "VcNvm"}
|
|
185
|
-
|
|
186
|
-
@staticmethod
|
|
187
|
-
def _compare_size(signal, widths):
|
|
188
|
-
"""Compare a json signal object with widths array.
|
|
189
|
-
|
|
190
|
-
:param signal: signal name
|
|
191
|
-
:param widths: array matrix size
|
|
192
|
-
:return: bool True if size is the same
|
|
193
|
-
|
|
194
|
-
"""
|
|
195
|
-
return signal["x_size"] == widths[0] and signal["y_size"] == widths[1]
|
|
196
|
-
|
|
197
|
-
@staticmethod
|
|
198
|
-
def _clean_values(widths):
|
|
199
|
-
"""Get clean width values.
|
|
200
|
-
|
|
201
|
-
Sometimes width array i set to -1,
|
|
202
|
-
(This data is read out from the simulink model in the matlab scripts,
|
|
203
|
-
-1 is simulink logic for the values should be inherited).
|
|
204
|
-
:param widths:
|
|
205
|
-
:return: a correct widths array
|
|
206
|
-
"""
|
|
207
|
-
if widths in ("-1", 1):
|
|
208
|
-
widths = [1, 1]
|
|
209
|
-
return widths
|
|
210
|
-
|
|
211
|
-
def _assert_data_type(self, signal, memory_area):
|
|
212
|
-
"""Asserts that each signal inside an NVM block is of one of the allowed data types of the block."""
|
|
213
|
-
memory_area_index = self._get_nvm_areas_index(memory_area)
|
|
214
|
-
if "NotApplicable" in self.nvm_definitions[memory_area_index]["allowed_datatypes"]:
|
|
215
|
-
# Special case for NVM_LIST_CRITICAL1 and 2. Any type is acceptable.
|
|
216
|
-
self.debug("Data type is not checked for %s", self.nvm_definitions[memory_area_index]["name"])
|
|
217
|
-
return
|
|
218
|
-
if signal["type"] not in self.nvm_definitions[memory_area_index]["allowed_datatypes"]:
|
|
219
|
-
msg = f"Signal type:{signal['type']} for {signal['name']} not allowed in area:{memory_area}"
|
|
220
|
-
self.critical(msg)
|
|
221
|
-
raise NVMDef.WrongTypeException(msg)
|
|
222
|
-
|
|
223
|
-
def _compare_signal(self, signal, data_type, widths, persistent_signal):
|
|
224
|
-
"""Compare signal and warn if there is a mismatch in data type or size.
|
|
225
|
-
|
|
226
|
-
:param signal: signal object from nvm_structs.json file
|
|
227
|
-
:param data_type: str
|
|
228
|
-
:param widths: array matrix size
|
|
229
|
-
:return: True if the signal is the same in both json struct and values read from simulink model.
|
|
230
|
-
|
|
231
|
-
"""
|
|
232
|
-
if data_type != signal["type"]:
|
|
233
|
-
log = self.critical if persistent_signal else self.warning
|
|
234
|
-
log("NVM signal: %s type mismatch %s != %s ", signal["name"], data_type, signal["type"])
|
|
235
|
-
return False
|
|
236
|
-
if not self._compare_size(signal, widths):
|
|
237
|
-
self.critical(
|
|
238
|
-
"signal:%s size mismatch %s != %s,%s ", signal["name"], widths, signal["x_size"], signal["y_size"]
|
|
239
|
-
)
|
|
240
|
-
return False
|
|
241
|
-
|
|
242
|
-
return True
|
|
243
|
-
|
|
244
|
-
def _get_nvm_areas_index(self, area):
|
|
245
|
-
"""Get array index of nvm area.
|
|
246
|
-
|
|
247
|
-
:param area: wanted nvm area as string
|
|
248
|
-
:return: (int) nvm areas index in self.nvm_definitions
|
|
249
|
-
"""
|
|
250
|
-
return next(
|
|
251
|
-
(index for index, nvm_definition in enumerate(self.nvm_definitions) if nvm_definition["name"] == area), -1
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
def _find_empty_index(self, memory_index, signal):
|
|
255
|
-
"""Find empty index in array of signals.
|
|
256
|
-
|
|
257
|
-
:param memory_index: array index (NVM area)
|
|
258
|
-
:param signal: signal to add at empty index
|
|
259
|
-
:return: (int) empty index, (-1 if not found)
|
|
260
|
-
"""
|
|
261
|
-
for signal_index in range(len(self.nvm_definitions[memory_index]["signals"])):
|
|
262
|
-
signal_candidate = self.nvm_definitions[memory_index]["signals"][signal_index]
|
|
263
|
-
if self._compare_size(signal, (signal_candidate["x_size"], signal_candidate["y_size"])) and (
|
|
264
|
-
signal_candidate["name"].startswith("Pos_") or signal_candidate["name"].startswith("Position_")
|
|
265
|
-
):
|
|
266
|
-
return signal_index
|
|
267
|
-
return -1
|
|
268
|
-
|
|
269
|
-
def _add_signal_to_nvm_struct(self, memory_index, signal_name, data_type, widths):
|
|
270
|
-
"""Add a signal to nvm struct at first empty index.
|
|
271
|
-
|
|
272
|
-
:param memory_index: array index (NVM area)
|
|
273
|
-
:param signal_name: str signal_nameiable name
|
|
274
|
-
:param data_type: str
|
|
275
|
-
:param widths: array matrix size
|
|
276
|
-
"""
|
|
277
|
-
if widths == "-1":
|
|
278
|
-
widths = [1, 1]
|
|
279
|
-
elif widths == "-":
|
|
280
|
-
self.critical("Bad widths value (%s), cannot add: %s", widths, signal_name)
|
|
281
|
-
return
|
|
282
|
-
|
|
283
|
-
new_signal = self._get_memory_area_signal_template(memory_index)
|
|
284
|
-
new_signal["name"] = signal_name
|
|
285
|
-
new_signal["type"] = data_type
|
|
286
|
-
new_signal["x_size"] = int(widths[0])
|
|
287
|
-
new_signal["y_size"] = int(widths[1])
|
|
288
|
-
signal_index = self._find_empty_index(memory_index, new_signal)
|
|
289
|
-
if signal_index > -1:
|
|
290
|
-
self.debug("Add at empty signal_index %s", signal_index)
|
|
291
|
-
self._update_nvm_signal(memory_index, signal_index, new_signal)
|
|
292
|
-
else:
|
|
293
|
-
self.nvm_definitions[memory_index]["signals"].append(new_signal)
|
|
294
|
-
|
|
295
|
-
def _get_signals_in_nvm_structs(self):
|
|
296
|
-
signals_in_nvm_structs = {}
|
|
297
|
-
for memory_area in self._nvm_memory_areas:
|
|
298
|
-
memory_area_index = self._get_nvm_areas_index(memory_area)
|
|
299
|
-
signals = self.nvm_definitions[memory_area_index]["signals"]
|
|
300
|
-
for signal_index, signal in enumerate(signals):
|
|
301
|
-
signals_in_nvm_structs.update(
|
|
302
|
-
{signal["name"]: {"memory_area": memory_area, "signal_index": signal_index}}
|
|
303
|
-
)
|
|
304
|
-
return signals_in_nvm_structs
|
|
305
|
-
|
|
306
|
-
def _dummify_nvm_signal(self, memory_area, signal_index):
|
|
307
|
-
dummy_name = f"Pos_{memory_area}bit{'_P' if memory_area.endswith('PER') else ''}_{signal_index}"
|
|
308
|
-
memory_index = self._get_nvm_areas_index(memory_area)
|
|
309
|
-
self.nvm_definitions[memory_index]["signals"][signal_index]["name"] = dummy_name
|
|
310
|
-
self.debug("Name of signal in nvm_structs.json was set to %s", dummy_name)
|
|
311
|
-
|
|
312
|
-
def _get_nvm_signal(self, memory_index, signal_index):
|
|
313
|
-
return self.nvm_definitions[memory_index]["signals"][signal_index]
|
|
314
|
-
|
|
315
|
-
def _update_nvm_signal(self, memory_index, signal_index, signal):
|
|
316
|
-
self.debug("Replacing %s with %s", self.nvm_definitions[memory_index]["signals"][signal_index], signal)
|
|
317
|
-
self.nvm_definitions[memory_index]["signals"][signal_index] = signal
|
|
318
|
-
|
|
319
|
-
def _update_duplicate_nvm_definition(self, nvm_structs_signals, model_signal, model_memory_area):
|
|
320
|
-
"""Check if already existing nvm signal is correctly configured."""
|
|
321
|
-
nvm_structs_memory_area = nvm_structs_signals[model_signal["name"]]["memory_area"]
|
|
322
|
-
nvm_structs_signal_index = nvm_structs_signals[model_signal["name"]]["signal_index"]
|
|
323
|
-
nvm_structs_memory_index = self._get_nvm_areas_index(nvm_structs_memory_area)
|
|
324
|
-
nvm_structs_signal = self._get_nvm_signal(nvm_structs_memory_index, nvm_structs_signal_index)
|
|
325
|
-
model_memory_index = self._get_nvm_areas_index(model_memory_area)
|
|
326
|
-
model_signal_widths = (model_signal["x_size"], model_signal["y_size"])
|
|
327
|
-
|
|
328
|
-
if "NVM_LIST_CRITICAL" in nvm_structs_memory_area:
|
|
329
|
-
# In this case, we need to update the signal memory area.
|
|
330
|
-
# _var_to_area cannot guess the right area for signals located in the critical sections due to varying data
|
|
331
|
-
# types
|
|
332
|
-
self.debug("Keeping signal %s in %s", model_signal["name"], nvm_structs_memory_area)
|
|
333
|
-
self._nvm_signals[model_signal["name"]]["area"] = nvm_structs_memory_area
|
|
334
|
-
return
|
|
335
|
-
|
|
336
|
-
persistent_signal = "_PER" in model_memory_area or "_PER" in nvm_structs_memory_area
|
|
337
|
-
if model_memory_area != nvm_structs_memory_area:
|
|
338
|
-
self.warning("NVM signal memory area mismatch for signal: '%s'", model_signal["name"])
|
|
339
|
-
self.warning("nvm_structs.json: '%s' - Memory area: %s", nvm_structs_memory_area, model_memory_area)
|
|
340
|
-
self._dummify_nvm_signal(nvm_structs_memory_area, nvm_structs_signal_index)
|
|
341
|
-
self._add_signal_to_nvm_struct(
|
|
342
|
-
model_memory_index, model_signal["name"], model_signal["type"], model_signal_widths
|
|
343
|
-
)
|
|
344
|
-
elif not self._compare_signal(nvm_structs_signal, model_signal["type"], model_signal_widths, persistent_signal):
|
|
345
|
-
if persistent_signal:
|
|
346
|
-
self.warning("NVM signal type or size mismatch for signal: '%s'", model_signal["name"])
|
|
347
|
-
self._dummify_nvm_signal(nvm_structs_memory_area, nvm_structs_signal_index)
|
|
348
|
-
self._add_signal_to_nvm_struct(
|
|
349
|
-
model_memory_index, model_signal["name"], model_signal["type"], model_signal_widths
|
|
350
|
-
)
|
|
351
|
-
self.warning("%s relocated to fitting position", model_signal["name"])
|
|
352
|
-
else:
|
|
353
|
-
self._update_nvm_signal(nvm_structs_memory_index, nvm_structs_signal_index, model_signal)
|
|
354
|
-
|
|
355
|
-
def _get_memory_area_signal_template(self, memory_area_index):
|
|
356
|
-
memory_area = self.nvm_definitions[memory_area_index]
|
|
357
|
-
signals = memory_area["signals"]
|
|
358
|
-
if signals:
|
|
359
|
-
return signals[0].copy()
|
|
360
|
-
|
|
361
|
-
return {"name": "", "type": "", "x_size": "", "y_size": ""}
|
|
362
|
-
|
|
363
|
-
def _update_nvm_base_struct(self):
|
|
364
|
-
"""Gather and update all nvm signals.
|
|
365
|
-
|
|
366
|
-
1) Updates existing signals,
|
|
367
|
-
2) Deletes/Dummy declares non- and persistent unused signals respectively,
|
|
368
|
-
3) Adds new signals,
|
|
369
|
-
in the nvm struct.
|
|
370
|
-
"""
|
|
371
|
-
|
|
372
|
-
def remove_unused_signals_from_nvm_struct():
|
|
373
|
-
"""Remove unused signals from the nvm struct.
|
|
374
|
-
|
|
375
|
-
The signals are listed in an array and accessed through calculated indices, therefore,
|
|
376
|
-
all unused signals must be removed at once.
|
|
377
|
-
"""
|
|
378
|
-
for mem_area in self._nvm_memory_areas:
|
|
379
|
-
mem_area_index = self._get_nvm_areas_index(mem_area)
|
|
380
|
-
unused_signals_in_area = [
|
|
381
|
-
signal_name
|
|
382
|
-
for signal_name, signal_info in unused_nvm_structs_signals.items()
|
|
383
|
-
if signal_info["memory_area"] == mem_area
|
|
384
|
-
]
|
|
385
|
-
|
|
386
|
-
# Cannot remove signals from the persistent memory areas,
|
|
387
|
-
# however, they can be exchanged for dummy signals
|
|
388
|
-
if "_PER" in self.nvm_definitions[mem_area_index]["name"]:
|
|
389
|
-
for unused_signal_name in unused_signals_in_area:
|
|
390
|
-
if unused_signal_name.startswith("Pos"):
|
|
391
|
-
self.debug("Found unused signal: '%s' in memory area: %s", unused_signal_name, mem_area)
|
|
392
|
-
else:
|
|
393
|
-
self.warning("Found unused signal: '%s' in memory area: %s", unused_signal_name, mem_area)
|
|
394
|
-
self._dummify_nvm_signal(
|
|
395
|
-
mem_area, unused_nvm_structs_signals[unused_signal_name]["signal_index"]
|
|
396
|
-
)
|
|
397
|
-
else:
|
|
398
|
-
self.nvm_definitions[mem_area_index]["signals"] = [
|
|
399
|
-
signal
|
|
400
|
-
for signal in self.nvm_definitions[mem_area_index]["signals"]
|
|
401
|
-
if signal["name"] not in unused_signals_in_area
|
|
402
|
-
]
|
|
403
|
-
|
|
404
|
-
nvm_structs_signals = self._get_signals_in_nvm_structs()
|
|
405
|
-
unused_nvm_structs_signals = self._get_signals_in_nvm_structs()
|
|
406
|
-
new_nvm_structs_signals = []
|
|
407
|
-
|
|
408
|
-
for nvm_memory_area in self._nvm_memory_areas:
|
|
409
|
-
memory_area_index = self._get_nvm_areas_index(nvm_memory_area)
|
|
410
|
-
if "NVM_LIST_CRITICAL" in nvm_memory_area:
|
|
411
|
-
# NVM_LIST_CRITICAL.* only exists in some projects
|
|
412
|
-
continue
|
|
413
|
-
if memory_area_index == -1:
|
|
414
|
-
self.critical("NVM area not found for: %s", nvm_memory_area)
|
|
415
|
-
continue
|
|
416
|
-
for nvm_data_type, nvm_signal_name, nvm_widths in self.nvm_area_iterator(nvm_memory_area):
|
|
417
|
-
nvm_widths = self._clean_values(nvm_widths)
|
|
418
|
-
nvm_signal = self._get_memory_area_signal_template(memory_area_index)
|
|
419
|
-
nvm_signal["name"] = nvm_signal_name
|
|
420
|
-
nvm_signal["type"] = nvm_data_type
|
|
421
|
-
nvm_signal["x_size"] = int(nvm_widths[0])
|
|
422
|
-
nvm_signal["y_size"] = int(nvm_widths[1])
|
|
423
|
-
if nvm_signal_name in nvm_structs_signals:
|
|
424
|
-
self.debug("Deleting %s", nvm_signal_name)
|
|
425
|
-
del unused_nvm_structs_signals[nvm_signal_name]
|
|
426
|
-
self._update_duplicate_nvm_definition(nvm_structs_signals, nvm_signal, nvm_memory_area)
|
|
427
|
-
else:
|
|
428
|
-
new_nvm_structs_signals.append((memory_area_index, nvm_signal["name"], nvm_data_type, nvm_widths))
|
|
429
|
-
remove_unused_signals_from_nvm_struct()
|
|
430
|
-
|
|
431
|
-
for new_signal in new_nvm_structs_signals:
|
|
432
|
-
self._add_signal_to_nvm_struct(*new_signal)
|
|
433
|
-
|
|
434
|
-
def _generate_nvm_structs_updated(self):
|
|
435
|
-
self.info("Start generating updated nvm json file")
|
|
436
|
-
|
|
437
|
-
nvm_structs_updated_path = os.path.abspath(
|
|
438
|
-
os.path.join(self._project_config.get_root_dir(), "output", "nvm_structs_updated.json")
|
|
439
|
-
)
|
|
440
|
-
|
|
441
|
-
self.info("Created %s", nvm_structs_updated_path)
|
|
442
|
-
|
|
443
|
-
with open(nvm_structs_updated_path, "w", encoding="utf-8") as nvm_structs_file:
|
|
444
|
-
json.dump(self.nvm_definitions, nvm_structs_file, indent=4)
|
|
445
|
-
|
|
446
|
-
def _get_struct_and_variable_name(self, memory_area, skip_prefix=False):
|
|
447
|
-
"""Get the name of the memory area struct and variable definitions."""
|
|
448
|
-
prefix = self._project_config.get_scheduler_prefix()
|
|
449
|
-
struct_name = f"{prefix}{memory_area}" if not skip_prefix else memory_area
|
|
450
|
-
if self._project_config.get_code_generation_config("useCamelCaseForNvmVariables"):
|
|
451
|
-
variable_name = "s" + "".join([part[0].upper() + part.lower()[1:] for part in struct_name.split("_")])
|
|
452
|
-
else:
|
|
453
|
-
variable_name = struct_name.lower()
|
|
454
|
-
return struct_name, variable_name
|
|
455
|
-
|
|
456
|
-
def _get_signal_and_struct_defines(self):
|
|
457
|
-
"""Get NVM signal and struct defines."""
|
|
458
|
-
defines = []
|
|
459
|
-
struct_defines = []
|
|
460
|
-
for memory_area in self._nvm_memory_areas:
|
|
461
|
-
struct_name, variable_name = self._get_struct_and_variable_name(memory_area)
|
|
462
|
-
memory_area_index = self._get_nvm_areas_index(memory_area)
|
|
463
|
-
section = self._area_section[memory_area]
|
|
464
|
-
elem_size = self._mem_area_elem_size[memory_area]
|
|
465
|
-
struct_defines.append(f'#include "{section}_START.h"\n')
|
|
466
|
-
struct_defines.append(f"struct {struct_name} {{\n")
|
|
467
|
-
|
|
468
|
-
struct_off = 0
|
|
469
|
-
signals = self.nvm_definitions[memory_area_index]["signals"]
|
|
470
|
-
for signal in signals:
|
|
471
|
-
self._assert_data_type(signal, memory_area)
|
|
472
|
-
struct_defines.append(f' {signal["type"]:7} {self.struct_member_prefix}{signal["name"]}')
|
|
473
|
-
size_string = ""
|
|
474
|
-
size = max(signal["x_size"], 1) * max(signal["y_size"], 1)
|
|
475
|
-
if size > 1:
|
|
476
|
-
if signal["x_size"] > 1:
|
|
477
|
-
size_string += f'[{signal["x_size"]}]'
|
|
478
|
-
if signal["y_size"] > 1:
|
|
479
|
-
if signal["x_size"] < 2:
|
|
480
|
-
self.critical("NVM signal size incorrect. x_size should not be 1 if y_size > 1")
|
|
481
|
-
size_string += "[1]"
|
|
482
|
-
size_string += f'[{signal["y_size"]}]'
|
|
483
|
-
struct_defines.append(size_string)
|
|
484
|
-
struct_defines.append(";\n")
|
|
485
|
-
|
|
486
|
-
if signal["name"] in self._nvm_signals:
|
|
487
|
-
self._nvm_signals[signal["name"]]["struct_off"] = struct_off
|
|
488
|
-
|
|
489
|
-
struct_off += size * byte_size(signal["type"])
|
|
490
|
-
|
|
491
|
-
defines.append(
|
|
492
|
-
"#define "
|
|
493
|
-
f"{signal['name']:40} "
|
|
494
|
-
f"{variable_name}.{self.struct_member_prefix}{signal['name']}\n"
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
max_nr_signals = self.nvm_definitions[memory_area_index]["size"]
|
|
498
|
-
tot_memory = max_nr_signals * elem_size
|
|
499
|
-
free = tot_memory - struct_off
|
|
500
|
-
if free > 0:
|
|
501
|
-
struct_defines.append(
|
|
502
|
-
f' {self.nvm_definitions[memory_area_index]["default_datatype"]} '
|
|
503
|
-
f'unused[{int(free / elem_size)}];\n'
|
|
504
|
-
)
|
|
505
|
-
elif free < 0:
|
|
506
|
-
self.critical("NVM area %s overrun!", self.nvm_definitions[memory_area_index]["name"])
|
|
507
|
-
struct_defines.append(f"}}; /* {struct_off} bytes used of {tot_memory} */\n")
|
|
508
|
-
struct_defines.append(f'#include "{section}_END.h"\n\n')
|
|
509
|
-
|
|
510
|
-
return defines, struct_defines
|
|
511
|
-
|
|
512
|
-
def _generate_nvm_config_headers(self):
|
|
513
|
-
"""Generate nvm config h file."""
|
|
514
|
-
self.info("Start generating nvm header file")
|
|
515
|
-
defines, struct_defines = self._get_signal_and_struct_defines()
|
|
516
|
-
|
|
517
|
-
externals = [f'#include "{self._predecl_start}"\n']
|
|
518
|
-
for area in self._nvm_memory_areas:
|
|
519
|
-
struct_name, variable_name = self._get_struct_and_variable_name(area)
|
|
520
|
-
externals.append(f"extern struct {struct_name} {variable_name};\n")
|
|
521
|
-
externals.append(f'#include "{self._predecl_end}"\n\n')
|
|
522
|
-
|
|
523
|
-
with open(self._file_name + ".h", "w", encoding="utf-8") as hptr:
|
|
524
|
-
hptr.write(self._nvm_header_head)
|
|
525
|
-
hptr.writelines(struct_defines)
|
|
526
|
-
hptr.writelines(externals)
|
|
527
|
-
hptr.write("\n")
|
|
528
|
-
hptr.writelines(defines)
|
|
529
|
-
hptr.write(self._nvm_header_footer)
|
|
530
|
-
|
|
531
|
-
def _generate_nvm_config_source(self):
|
|
532
|
-
"""Generate the c-file containing the NVM definition."""
|
|
533
|
-
# TODO: Add memory from previous builds!!! and mark old positions #
|
|
534
|
-
self.info("Start generating nvm source file")
|
|
535
|
-
with open(self._file_name + ".c", "w", encoding="utf-8") as cptr:
|
|
536
|
-
cptr.write(f'#include "{self._nvm_defs["fileName"]}.h"\n\n')
|
|
537
|
-
for area, pragma in zip(self._nvm_memory_areas, self._mem_area_pragmas):
|
|
538
|
-
struct_name, variable_name = self._get_struct_and_variable_name(area)
|
|
539
|
-
cptr.write(f'#include "{pragma[0]}"\n')
|
|
540
|
-
cptr.write(f"struct {struct_name} {variable_name};\n")
|
|
541
|
-
cptr.write(f'#include "{pragma[1]}"\n\n')
|
|
542
|
-
|
|
543
|
-
def _generate_nvm_config_a2l(self):
|
|
544
|
-
"""Generate the a2l-file describing the NVM definition."""
|
|
545
|
-
self.info("Start generating nvm a2l file")
|
|
546
|
-
a2l_dict = self._a2l_dict()
|
|
547
|
-
a2l = A2l(a2l_dict, self._project_config)
|
|
548
|
-
a2l.gen_a2l(self._file_name + ".a2l")
|
|
549
|
-
|
|
550
|
-
def generate_nvm_config_files(self, no_nvm_a2l):
|
|
551
|
-
"""Generate all files for variables in the NVM definition.
|
|
552
|
-
|
|
553
|
-
Args:
|
|
554
|
-
no_nvm_a2l (bool): Do not generate a2l file.
|
|
555
|
-
"""
|
|
556
|
-
self._update_nvm_base_struct()
|
|
557
|
-
self._generate_nvm_structs_updated()
|
|
558
|
-
self._generate_nvm_config_headers()
|
|
559
|
-
self._generate_nvm_config_source()
|
|
560
|
-
if not no_nvm_a2l:
|
|
561
|
-
self._generate_nvm_config_a2l()
|
|
562
|
-
|
|
563
|
-
@staticmethod
|
|
564
|
-
def _get_signal_list(signals):
|
|
565
|
-
return signals if isinstance(signals, list) else [signals]
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
class ZCNVMDef(NVMDef):
|
|
569
|
-
"""A class for handling of ZC NVM definitions."""
|
|
570
|
-
|
|
571
|
-
def __init__(self, project_config, unit_cfg, nvm_vars):
|
|
572
|
-
"""Init.
|
|
573
|
-
|
|
574
|
-
Args:
|
|
575
|
-
project_config (BuildProjConfig): current project configuration.
|
|
576
|
-
unit_cfg (UnitConfigs): Unit configurations.
|
|
577
|
-
nvm_vars (dict): NVM variables from unit configurations.
|
|
578
|
-
"""
|
|
579
|
-
super().__init__(project_config, unit_cfg, nvm_vars)
|
|
580
|
-
self.struct_member_prefix = "e_"
|
|
581
|
-
self._valid_nvm_definitions = None
|
|
582
|
-
self._update_nvm_base_struct()
|
|
583
|
-
prefix = self._project_config.get_scheduler_prefix()
|
|
584
|
-
self.project_nvm_definitions = {
|
|
585
|
-
f"{prefix}{item['name']}": item for item in self.nvm_definitions
|
|
586
|
-
}
|
|
587
|
-
self._predecl_start = bd.PREDECL_NVM_START
|
|
588
|
-
self._predecl_end = bd.PREDECL_NVM_END
|
|
589
|
-
self.init_function = f"void {prefix}VcNvmInit(void)"
|
|
590
|
-
self.main_function = f"void {prefix}VcNvm(void)"
|
|
591
|
-
|
|
592
|
-
@property
|
|
593
|
-
def valid_nvm_definitions(self):
|
|
594
|
-
"""Get the valid NVM definitions."""
|
|
595
|
-
return self._valid_nvm_definitions
|
|
596
|
-
|
|
597
|
-
@valid_nvm_definitions.setter
|
|
598
|
-
def valid_nvm_definitions(self, yaml_nvm_definitions):
|
|
599
|
-
"""Return a set of NVM definitions appearing in both the project and the project yaml file.
|
|
600
|
-
|
|
601
|
-
Args:
|
|
602
|
-
yaml_nvm_definitions (dict): NVM lists listed in the NVM configuration yaml file.
|
|
603
|
-
Returns:
|
|
604
|
-
valid_nvm_definitions (dict): Validated NVM definitions,
|
|
605
|
-
listed in both NVM configuration yaml file as well as project.
|
|
606
|
-
"""
|
|
607
|
-
local_yaml_nvm_definitions = deepcopy(yaml_nvm_definitions)
|
|
608
|
-
nvms_not_in_project = set(local_yaml_nvm_definitions.keys()) - set(self.project_nvm_definitions.keys())
|
|
609
|
-
nvms_not_in_yaml = set(self.project_nvm_definitions.keys()) - set(local_yaml_nvm_definitions.keys())
|
|
610
|
-
for key in nvms_not_in_project:
|
|
611
|
-
self.warning(f'Ignoring NVM definition {key} since it does not appear in nvm_structs.json.')
|
|
612
|
-
del local_yaml_nvm_definitions[key]
|
|
613
|
-
for key in nvms_not_in_yaml:
|
|
614
|
-
self.warning(f'Ignoring NVM definition {key} since it does not appear in the project NVM yaml file.')
|
|
615
|
-
self._valid_nvm_definitions = local_yaml_nvm_definitions
|
|
616
|
-
|
|
617
|
-
def _update_header_and_footer(self):
|
|
618
|
-
name = self._project_config.get_composition_config("softwareComponentName")
|
|
619
|
-
use_rte_nvm_structs = self._project_config.get_code_generation_config("useRteNvmStructs")
|
|
620
|
-
self._nvm_header_head += f'#include "Rte_{name}.h"\n'
|
|
621
|
-
if use_rte_nvm_structs:
|
|
622
|
-
self._nvm_header_head += '#include "Rte_Type.h"\n\n'
|
|
623
|
-
self._nvm_header_footer = (
|
|
624
|
-
"\n"
|
|
625
|
-
f'#include "{bd.PREDECL_CODE_ASIL_D_START}"\n'
|
|
626
|
-
f"{self.init_function};\n"
|
|
627
|
-
f"{self.main_function};\n"
|
|
628
|
-
f'#include "{bd.PREDECL_CODE_ASIL_D_END}"\n'
|
|
629
|
-
f"{self._nvm_header_footer}"
|
|
630
|
-
)
|
|
631
|
-
|
|
632
|
-
def _generate_rte_type_nvm_config_headers(self):
|
|
633
|
-
"""Generate NVM config header file using RTE struct definitions."""
|
|
634
|
-
self.info("Start generating nvm header file")
|
|
635
|
-
defines = self._get_signal_and_struct_defines()[0]
|
|
636
|
-
externals = [f'#include "{self._predecl_start}"\n']
|
|
637
|
-
for area in self.valid_nvm_definitions.keys():
|
|
638
|
-
struct_name, variable_name = self._get_struct_and_variable_name(area, skip_prefix=True)
|
|
639
|
-
externals.append(f"extern dt_{struct_name} {variable_name};\n")
|
|
640
|
-
externals.append(f'#include "{self._predecl_end}"\n\n')
|
|
641
|
-
with open(self._file_name + ".h", "w", encoding="utf-8") as hptr:
|
|
642
|
-
hptr.write(self._nvm_header_head)
|
|
643
|
-
hptr.writelines(externals)
|
|
644
|
-
hptr.writelines(defines)
|
|
645
|
-
hptr.write(self._nvm_header_footer)
|
|
646
|
-
|
|
647
|
-
def _generate_rte_type_nvm_config_source(self):
|
|
648
|
-
"""Generate the c-file containing the NVM definition using RTE struct definitions."""
|
|
649
|
-
# TODO: Add memory from previous builds!!! and mark old positions #
|
|
650
|
-
self.info("Start generating nvm source file")
|
|
651
|
-
with open(self._file_name + ".c", "w", encoding="utf-8") as cptr:
|
|
652
|
-
cptr.write(f'#include "{self._nvm_defs["fileName"]}.h"\n\n')
|
|
653
|
-
for area, pragma in zip(self._nvm_memory_areas, self._mem_area_pragmas):
|
|
654
|
-
struct_name, variable_name = self._get_struct_and_variable_name(area)
|
|
655
|
-
if struct_name in self.valid_nvm_definitions:
|
|
656
|
-
cptr.write(f'#include "{pragma[0]}"\n')
|
|
657
|
-
cptr.write(f"dt_{struct_name} {variable_name};\n")
|
|
658
|
-
cptr.write(f'#include "{pragma[1]}"\n\n')
|
|
659
|
-
|
|
660
|
-
def _append_nvm_rte_function_calls(self):
|
|
661
|
-
"""Append the NVM RTE function calls to the NVM config source file."""
|
|
662
|
-
init_function_lines = [
|
|
663
|
-
f'#include "{bd.CVC_CODE_ASIL_D_START}"\n'
|
|
664
|
-
f"{self.init_function} {{\n",
|
|
665
|
-
" //Call this function in the SWC init runnable\n"
|
|
666
|
-
]
|
|
667
|
-
main_function = [
|
|
668
|
-
f'#include "{bd.CVC_CODE_ASIL_D_START}"\n'
|
|
669
|
-
f"{self.main_function} {{\n",
|
|
670
|
-
" //Call this function in the SWC main runnable\n",
|
|
671
|
-
]
|
|
672
|
-
footer = [
|
|
673
|
-
"}\n",
|
|
674
|
-
f'#include "{bd.CVC_CODE_ASIL_D_END}"\n',
|
|
675
|
-
]
|
|
676
|
-
|
|
677
|
-
main_function_lines = []
|
|
678
|
-
|
|
679
|
-
for nvm_name, nvm_data in self.valid_nvm_definitions.items():
|
|
680
|
-
if nvm_data["type"] not in ["type1", "type2"]:
|
|
681
|
-
self.critical(f"Unknown NVM type: {nvm_data['type']} for NVM: {nvm_name}")
|
|
682
|
-
continue
|
|
683
|
-
if nvm_data["method"] not in ["DIRECT-CALL", "NVSWCOMPONENT"]:
|
|
684
|
-
self.critical(f"Unknown NVM method: {nvm_data['method']} for NVM: {nvm_name}")
|
|
685
|
-
continue
|
|
686
|
-
|
|
687
|
-
if nvm_data["type"] == "type2":
|
|
688
|
-
self.warning(
|
|
689
|
-
f'{nvm_name} is a type2 {nvm_data["method"]}. Due to inherent risk type2 write calls are '
|
|
690
|
-
'not generated automatically, they have to be written manually and added to source code.'
|
|
691
|
-
)
|
|
692
|
-
main_function_lines.append(
|
|
693
|
-
f" // Nvm {nvm_name} is type 2, add call in manually written source code.\n"
|
|
694
|
-
)
|
|
695
|
-
elif nvm_data["type"] == "type1":
|
|
696
|
-
variable_name = self._get_struct_and_variable_name(nvm_name, skip_prefix=True)[1]
|
|
697
|
-
if nvm_data["method"] == "DIRECT-CALL":
|
|
698
|
-
pim_call = f"Rte_Pim_{nvm_name}()"
|
|
699
|
-
main_function_lines.append(f" *{pim_call} = {variable_name};\n")
|
|
700
|
-
init_function_lines.append(f" {variable_name} = *{pim_call};\n")
|
|
701
|
-
elif nvm_data["method"] == "NVSWCOMPONENT":
|
|
702
|
-
init_function_lines.append(
|
|
703
|
-
f" Rte_Read_{nvm_name.upper()}_{nvm_name.upper()}(&{variable_name});\n"
|
|
704
|
-
)
|
|
705
|
-
main_function.append(
|
|
706
|
-
f" Rte_Write_{nvm_name.upper()}_{nvm_name.upper()}(&{variable_name});\n"
|
|
707
|
-
)
|
|
708
|
-
|
|
709
|
-
output = init_function_lines + footer + ["\n"] + main_function + main_function_lines + footer
|
|
710
|
-
with open(self._file_name + ".c", mode="a", encoding="utf-8") as cptr:
|
|
711
|
-
cptr.writelines(output)
|
|
712
|
-
|
|
713
|
-
def generate_nvm_rte_files(self):
|
|
714
|
-
"""Generate the NVM RTE files."""
|
|
715
|
-
if self.valid_nvm_definitions is None:
|
|
716
|
-
self.critical('Valid NVM definitions not set. Cannot generate NVM RTE files.')
|
|
717
|
-
return
|
|
718
|
-
|
|
719
|
-
use_rte_nvm_structs = self._project_config.get_code_generation_config("useRteNvmStructs")
|
|
720
|
-
|
|
721
|
-
self._update_header_and_footer()
|
|
722
|
-
self._generate_nvm_structs_updated()
|
|
723
|
-
if use_rte_nvm_structs:
|
|
724
|
-
self._generate_rte_type_nvm_config_headers()
|
|
725
|
-
self._generate_rte_type_nvm_config_source()
|
|
726
|
-
else:
|
|
727
|
-
self._generate_nvm_config_headers()
|
|
728
|
-
self._generate_nvm_config_source()
|
|
729
|
-
self._append_nvm_rte_function_calls()
|
|
1
|
+
# Copyright 2024 Volvo Car Corporation
|
|
2
|
+
# Licensed under Apache 2.0.
|
|
3
|
+
|
|
4
|
+
# -*- coding: utf-8 -*-
|
|
5
|
+
"""Module for handling of NVM definitions and for generation of c&h-files defining the memory layout of the NVM."""
|
|
6
|
+
import re
|
|
7
|
+
import os
|
|
8
|
+
import json
|
|
9
|
+
from copy import deepcopy
|
|
10
|
+
|
|
11
|
+
import powertrain_build.build_defs as bd
|
|
12
|
+
from powertrain_build.types import byte_size, get_bitmask
|
|
13
|
+
from powertrain_build.a2l import A2l
|
|
14
|
+
from powertrain_build.problem_logger import ProblemLogger
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class NVMDef(ProblemLogger):
|
|
18
|
+
"""A class that holds the NVM definitions for the build.
|
|
19
|
+
|
|
20
|
+
Provides methods for generating NVM structs and header files.
|
|
21
|
+
The header files includes defines which reference the
|
|
22
|
+
struct elements as variables.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
class WrongTypeException(Exception):
|
|
26
|
+
"""WrongTypeException."""
|
|
27
|
+
|
|
28
|
+
_allowed_nvm_memory_areas = [
|
|
29
|
+
"NVM_LIST_32",
|
|
30
|
+
"NVM_LIST_16",
|
|
31
|
+
"NVM_LIST_8",
|
|
32
|
+
"NVM_LIST_32_PER",
|
|
33
|
+
"NVM_LIST_16_PER",
|
|
34
|
+
"NVM_LIST_8_PER",
|
|
35
|
+
"NVM_LIST_CRITICAL1",
|
|
36
|
+
"NVM_LIST_CRITICAL2",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
_nvm_header_footer = "\n#endif /* VCC_NVM_STRUCT_H */\n"
|
|
40
|
+
|
|
41
|
+
def __init__(self, project_config, unit_cfg, nvm_vars):
|
|
42
|
+
"""Constructor.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
project_config (BuildProjConfig): current project configuration
|
|
46
|
+
unit_cfg (UnitConfigs): unit definitions
|
|
47
|
+
nvm_vars (dict): NVM variables from unit configurations (:doc:`UnitConfigs <unit_configs>`)
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
super().__init__()
|
|
51
|
+
self._project_config = project_config
|
|
52
|
+
self._nvm_vars = nvm_vars
|
|
53
|
+
# get the size of areas and c-file names
|
|
54
|
+
self._nvm_defs = project_config.get_nvm_defs()
|
|
55
|
+
self._nvm_signals = {}
|
|
56
|
+
self._nvm_memory_areas = tuple()
|
|
57
|
+
self._mem_area_elem_size = {}
|
|
58
|
+
self._area_section = {}
|
|
59
|
+
self._mem_area_pragmas = tuple()
|
|
60
|
+
self._nvm_header_head = self._get_nvm_header_head(unit_cfg)
|
|
61
|
+
src_file_dst = self._project_config.get_src_code_dst_dir()
|
|
62
|
+
self._file_name = os.path.join(src_file_dst, self._nvm_defs["fileName"])
|
|
63
|
+
self._predecl_start = bd.PREDECL_START
|
|
64
|
+
self._predecl_end = bd.PREDECL_END
|
|
65
|
+
self.struct_member_prefix = "_"
|
|
66
|
+
|
|
67
|
+
with open(
|
|
68
|
+
os.path.join(project_config.get_root_dir(), self._nvm_defs["baseNvmStructs"]), "r", encoding="utf-8"
|
|
69
|
+
) as nvm_json:
|
|
70
|
+
self.nvm_definitions = json.load(nvm_json)
|
|
71
|
+
for memory_area in self.nvm_definitions:
|
|
72
|
+
self._add_memory_area(memory_area)
|
|
73
|
+
self._order_nvm_per_area()
|
|
74
|
+
for memory_area in self.nvm_definitions:
|
|
75
|
+
memory_index = self._get_nvm_areas_index(memory_area["name"])
|
|
76
|
+
self.info("Updating %s with index %s", memory_area["name"], memory_index)
|
|
77
|
+
self.nvm_definitions[memory_index]["signals"] = self._get_signal_list(memory_area["signals"])
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def _get_nvm_header_head(unit_cfg):
|
|
81
|
+
_nvm_header_head = (
|
|
82
|
+
"/*\n"
|
|
83
|
+
" * vcc_nvm_struct.h - struct for NVM signals\n"
|
|
84
|
+
" */\n\n"
|
|
85
|
+
"#ifndef VCC_NVM_STRUCT_H\n"
|
|
86
|
+
"#define VCC_NVM_STRUCT_H\n\n"
|
|
87
|
+
)
|
|
88
|
+
_nvm_header_head += unit_cfg.base_types_headers
|
|
89
|
+
return _nvm_header_head
|
|
90
|
+
|
|
91
|
+
def _add_memory_area(self, memory_area):
|
|
92
|
+
"""Add non-default areas."""
|
|
93
|
+
if memory_area["name"] not in self._allowed_nvm_memory_areas:
|
|
94
|
+
msg = f"Memory area: {memory_area['name']} not allowed"
|
|
95
|
+
self.critical(msg)
|
|
96
|
+
raise NVMDef.WrongTypeException(msg)
|
|
97
|
+
|
|
98
|
+
self._nvm_memory_areas = (*self._nvm_memory_areas, memory_area["name"])
|
|
99
|
+
self._mem_area_elem_size.update({memory_area["name"]: byte_size(memory_area["default_datatype"])})
|
|
100
|
+
|
|
101
|
+
if memory_area["persistent"]:
|
|
102
|
+
self._area_section.update({memory_area["name"]: "CVC_NVM_P"})
|
|
103
|
+
self._mem_area_pragmas = (*self._mem_area_pragmas, (bd.CVC_NVM_P_START, bd.CVC_NVM_P_END))
|
|
104
|
+
else:
|
|
105
|
+
self._area_section.update({memory_area["name"]: "CVC_NVM"})
|
|
106
|
+
self._mem_area_pragmas = (*self._mem_area_pragmas, (bd.CVC_NVM_START, bd.CVC_NVM_END))
|
|
107
|
+
|
|
108
|
+
def _var_to_area(self, var_info):
|
|
109
|
+
"""Find the NVM area for the variable.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
var_info (dict): a dict with the variable attributes.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
area (str): a string with the area the variable should be
|
|
116
|
+
defined in.
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
mtch = re.match(r"\D+(\d+)?", var_info["type"])
|
|
120
|
+
if mtch.group(1) is None:
|
|
121
|
+
size = "8"
|
|
122
|
+
else:
|
|
123
|
+
size = mtch.group(1)
|
|
124
|
+
if var_info["class"] == "CVC_DISP_NVM":
|
|
125
|
+
return "NVM_LIST_" + size
|
|
126
|
+
if var_info["class"] == "CVC_DISP_NVM_P":
|
|
127
|
+
return "NVM_LIST_" + size + "_PER"
|
|
128
|
+
self.critical("%s is not a NVM variable!", var_info["name"])
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
def _order_nvm_per_area(self):
|
|
132
|
+
"""Order the NVM in the areas, based on the definitions."""
|
|
133
|
+
for var, unit_attrib in self._nvm_vars.items():
|
|
134
|
+
for _, var_attribs in unit_attrib.items():
|
|
135
|
+
area = self._var_to_area(var_attribs)
|
|
136
|
+
self._nvm_signals[var] = var_attribs
|
|
137
|
+
self._nvm_signals[var]["area"] = area
|
|
138
|
+
# only use one units definition
|
|
139
|
+
# TODO:Make a nicer solution #
|
|
140
|
+
break
|
|
141
|
+
|
|
142
|
+
def nvm_area_iterator(self, nvm_area_name):
|
|
143
|
+
"""Get an iterator for NVM 'area'.
|
|
144
|
+
|
|
145
|
+
The iterator yields data_type and and variable name for the
|
|
146
|
+
variables defined in the area.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
nvm_area_name (str): the name of the NVM area
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
tuple: (data_type, variable name, size)
|
|
153
|
+
|
|
154
|
+
"""
|
|
155
|
+
for nvm_signal_name, nvm_attributes in self._nvm_signals.items():
|
|
156
|
+
if nvm_attributes["area"] == nvm_area_name:
|
|
157
|
+
yield nvm_attributes.get("type"), nvm_signal_name, nvm_attributes.get("width", 1)
|
|
158
|
+
|
|
159
|
+
def _a2l_dict(self):
|
|
160
|
+
"""Return a dict defining all parameters for a2l-generation."""
|
|
161
|
+
res = {}
|
|
162
|
+
for var, var_attrib in self._nvm_signals.items():
|
|
163
|
+
variable_name = self._get_struct_and_variable_name(var_attrib["area"])[1]
|
|
164
|
+
res[var] = {
|
|
165
|
+
"var": {"var": var, "type": var_attrib["type"], "cvc_type": "CVC_NVM"},
|
|
166
|
+
"a2l_data": {
|
|
167
|
+
"bitmask": get_bitmask(var_attrib["type"]),
|
|
168
|
+
"description": var_attrib["description"],
|
|
169
|
+
"lsb": var_attrib.get("lsb", 1),
|
|
170
|
+
"max": var_attrib.get("max"),
|
|
171
|
+
"min": var_attrib.get("min"),
|
|
172
|
+
"offset": var_attrib.get("offset"),
|
|
173
|
+
"unit": var_attrib["unit"],
|
|
174
|
+
"symbol": variable_name,
|
|
175
|
+
"symbol_offset": var_attrib.get("struct_off"),
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
width = var_attrib.get("width", 1)
|
|
179
|
+
if width:
|
|
180
|
+
if isinstance(width, list):
|
|
181
|
+
res[var]["array"] = width
|
|
182
|
+
elif int(width) > 1:
|
|
183
|
+
res[var]["array"] = [width]
|
|
184
|
+
return {"vars": res, "function": "VcNvm"}
|
|
185
|
+
|
|
186
|
+
@staticmethod
|
|
187
|
+
def _compare_size(signal, widths):
|
|
188
|
+
"""Compare a json signal object with widths array.
|
|
189
|
+
|
|
190
|
+
:param signal: signal name
|
|
191
|
+
:param widths: array matrix size
|
|
192
|
+
:return: bool True if size is the same
|
|
193
|
+
|
|
194
|
+
"""
|
|
195
|
+
return signal["x_size"] == widths[0] and signal["y_size"] == widths[1]
|
|
196
|
+
|
|
197
|
+
@staticmethod
|
|
198
|
+
def _clean_values(widths):
|
|
199
|
+
"""Get clean width values.
|
|
200
|
+
|
|
201
|
+
Sometimes width array i set to -1,
|
|
202
|
+
(This data is read out from the simulink model in the matlab scripts,
|
|
203
|
+
-1 is simulink logic for the values should be inherited).
|
|
204
|
+
:param widths:
|
|
205
|
+
:return: a correct widths array
|
|
206
|
+
"""
|
|
207
|
+
if widths in ("-1", 1):
|
|
208
|
+
widths = [1, 1]
|
|
209
|
+
return widths
|
|
210
|
+
|
|
211
|
+
def _assert_data_type(self, signal, memory_area):
|
|
212
|
+
"""Asserts that each signal inside an NVM block is of one of the allowed data types of the block."""
|
|
213
|
+
memory_area_index = self._get_nvm_areas_index(memory_area)
|
|
214
|
+
if "NotApplicable" in self.nvm_definitions[memory_area_index]["allowed_datatypes"]:
|
|
215
|
+
# Special case for NVM_LIST_CRITICAL1 and 2. Any type is acceptable.
|
|
216
|
+
self.debug("Data type is not checked for %s", self.nvm_definitions[memory_area_index]["name"])
|
|
217
|
+
return
|
|
218
|
+
if signal["type"] not in self.nvm_definitions[memory_area_index]["allowed_datatypes"]:
|
|
219
|
+
msg = f"Signal type:{signal['type']} for {signal['name']} not allowed in area:{memory_area}"
|
|
220
|
+
self.critical(msg)
|
|
221
|
+
raise NVMDef.WrongTypeException(msg)
|
|
222
|
+
|
|
223
|
+
def _compare_signal(self, signal, data_type, widths, persistent_signal):
|
|
224
|
+
"""Compare signal and warn if there is a mismatch in data type or size.
|
|
225
|
+
|
|
226
|
+
:param signal: signal object from nvm_structs.json file
|
|
227
|
+
:param data_type: str
|
|
228
|
+
:param widths: array matrix size
|
|
229
|
+
:return: True if the signal is the same in both json struct and values read from simulink model.
|
|
230
|
+
|
|
231
|
+
"""
|
|
232
|
+
if data_type != signal["type"]:
|
|
233
|
+
log = self.critical if persistent_signal else self.warning
|
|
234
|
+
log("NVM signal: %s type mismatch %s != %s ", signal["name"], data_type, signal["type"])
|
|
235
|
+
return False
|
|
236
|
+
if not self._compare_size(signal, widths):
|
|
237
|
+
self.critical(
|
|
238
|
+
"signal:%s size mismatch %s != %s,%s ", signal["name"], widths, signal["x_size"], signal["y_size"]
|
|
239
|
+
)
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
return True
|
|
243
|
+
|
|
244
|
+
def _get_nvm_areas_index(self, area):
|
|
245
|
+
"""Get array index of nvm area.
|
|
246
|
+
|
|
247
|
+
:param area: wanted nvm area as string
|
|
248
|
+
:return: (int) nvm areas index in self.nvm_definitions
|
|
249
|
+
"""
|
|
250
|
+
return next(
|
|
251
|
+
(index for index, nvm_definition in enumerate(self.nvm_definitions) if nvm_definition["name"] == area), -1
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
def _find_empty_index(self, memory_index, signal):
|
|
255
|
+
"""Find empty index in array of signals.
|
|
256
|
+
|
|
257
|
+
:param memory_index: array index (NVM area)
|
|
258
|
+
:param signal: signal to add at empty index
|
|
259
|
+
:return: (int) empty index, (-1 if not found)
|
|
260
|
+
"""
|
|
261
|
+
for signal_index in range(len(self.nvm_definitions[memory_index]["signals"])):
|
|
262
|
+
signal_candidate = self.nvm_definitions[memory_index]["signals"][signal_index]
|
|
263
|
+
if self._compare_size(signal, (signal_candidate["x_size"], signal_candidate["y_size"])) and (
|
|
264
|
+
signal_candidate["name"].startswith("Pos_") or signal_candidate["name"].startswith("Position_")
|
|
265
|
+
):
|
|
266
|
+
return signal_index
|
|
267
|
+
return -1
|
|
268
|
+
|
|
269
|
+
def _add_signal_to_nvm_struct(self, memory_index, signal_name, data_type, widths):
|
|
270
|
+
"""Add a signal to nvm struct at first empty index.
|
|
271
|
+
|
|
272
|
+
:param memory_index: array index (NVM area)
|
|
273
|
+
:param signal_name: str signal_nameiable name
|
|
274
|
+
:param data_type: str
|
|
275
|
+
:param widths: array matrix size
|
|
276
|
+
"""
|
|
277
|
+
if widths == "-1":
|
|
278
|
+
widths = [1, 1]
|
|
279
|
+
elif widths == "-":
|
|
280
|
+
self.critical("Bad widths value (%s), cannot add: %s", widths, signal_name)
|
|
281
|
+
return
|
|
282
|
+
|
|
283
|
+
new_signal = self._get_memory_area_signal_template(memory_index)
|
|
284
|
+
new_signal["name"] = signal_name
|
|
285
|
+
new_signal["type"] = data_type
|
|
286
|
+
new_signal["x_size"] = int(widths[0])
|
|
287
|
+
new_signal["y_size"] = int(widths[1])
|
|
288
|
+
signal_index = self._find_empty_index(memory_index, new_signal)
|
|
289
|
+
if signal_index > -1:
|
|
290
|
+
self.debug("Add at empty signal_index %s", signal_index)
|
|
291
|
+
self._update_nvm_signal(memory_index, signal_index, new_signal)
|
|
292
|
+
else:
|
|
293
|
+
self.nvm_definitions[memory_index]["signals"].append(new_signal)
|
|
294
|
+
|
|
295
|
+
def _get_signals_in_nvm_structs(self):
|
|
296
|
+
signals_in_nvm_structs = {}
|
|
297
|
+
for memory_area in self._nvm_memory_areas:
|
|
298
|
+
memory_area_index = self._get_nvm_areas_index(memory_area)
|
|
299
|
+
signals = self.nvm_definitions[memory_area_index]["signals"]
|
|
300
|
+
for signal_index, signal in enumerate(signals):
|
|
301
|
+
signals_in_nvm_structs.update(
|
|
302
|
+
{signal["name"]: {"memory_area": memory_area, "signal_index": signal_index}}
|
|
303
|
+
)
|
|
304
|
+
return signals_in_nvm_structs
|
|
305
|
+
|
|
306
|
+
def _dummify_nvm_signal(self, memory_area, signal_index):
|
|
307
|
+
dummy_name = f"Pos_{memory_area}bit{'_P' if memory_area.endswith('PER') else ''}_{signal_index}"
|
|
308
|
+
memory_index = self._get_nvm_areas_index(memory_area)
|
|
309
|
+
self.nvm_definitions[memory_index]["signals"][signal_index]["name"] = dummy_name
|
|
310
|
+
self.debug("Name of signal in nvm_structs.json was set to %s", dummy_name)
|
|
311
|
+
|
|
312
|
+
def _get_nvm_signal(self, memory_index, signal_index):
|
|
313
|
+
return self.nvm_definitions[memory_index]["signals"][signal_index]
|
|
314
|
+
|
|
315
|
+
def _update_nvm_signal(self, memory_index, signal_index, signal):
|
|
316
|
+
self.debug("Replacing %s with %s", self.nvm_definitions[memory_index]["signals"][signal_index], signal)
|
|
317
|
+
self.nvm_definitions[memory_index]["signals"][signal_index] = signal
|
|
318
|
+
|
|
319
|
+
def _update_duplicate_nvm_definition(self, nvm_structs_signals, model_signal, model_memory_area):
|
|
320
|
+
"""Check if already existing nvm signal is correctly configured."""
|
|
321
|
+
nvm_structs_memory_area = nvm_structs_signals[model_signal["name"]]["memory_area"]
|
|
322
|
+
nvm_structs_signal_index = nvm_structs_signals[model_signal["name"]]["signal_index"]
|
|
323
|
+
nvm_structs_memory_index = self._get_nvm_areas_index(nvm_structs_memory_area)
|
|
324
|
+
nvm_structs_signal = self._get_nvm_signal(nvm_structs_memory_index, nvm_structs_signal_index)
|
|
325
|
+
model_memory_index = self._get_nvm_areas_index(model_memory_area)
|
|
326
|
+
model_signal_widths = (model_signal["x_size"], model_signal["y_size"])
|
|
327
|
+
|
|
328
|
+
if "NVM_LIST_CRITICAL" in nvm_structs_memory_area:
|
|
329
|
+
# In this case, we need to update the signal memory area.
|
|
330
|
+
# _var_to_area cannot guess the right area for signals located in the critical sections due to varying data
|
|
331
|
+
# types
|
|
332
|
+
self.debug("Keeping signal %s in %s", model_signal["name"], nvm_structs_memory_area)
|
|
333
|
+
self._nvm_signals[model_signal["name"]]["area"] = nvm_structs_memory_area
|
|
334
|
+
return
|
|
335
|
+
|
|
336
|
+
persistent_signal = "_PER" in model_memory_area or "_PER" in nvm_structs_memory_area
|
|
337
|
+
if model_memory_area != nvm_structs_memory_area:
|
|
338
|
+
self.warning("NVM signal memory area mismatch for signal: '%s'", model_signal["name"])
|
|
339
|
+
self.warning("nvm_structs.json: '%s' - Memory area: %s", nvm_structs_memory_area, model_memory_area)
|
|
340
|
+
self._dummify_nvm_signal(nvm_structs_memory_area, nvm_structs_signal_index)
|
|
341
|
+
self._add_signal_to_nvm_struct(
|
|
342
|
+
model_memory_index, model_signal["name"], model_signal["type"], model_signal_widths
|
|
343
|
+
)
|
|
344
|
+
elif not self._compare_signal(nvm_structs_signal, model_signal["type"], model_signal_widths, persistent_signal):
|
|
345
|
+
if persistent_signal:
|
|
346
|
+
self.warning("NVM signal type or size mismatch for signal: '%s'", model_signal["name"])
|
|
347
|
+
self._dummify_nvm_signal(nvm_structs_memory_area, nvm_structs_signal_index)
|
|
348
|
+
self._add_signal_to_nvm_struct(
|
|
349
|
+
model_memory_index, model_signal["name"], model_signal["type"], model_signal_widths
|
|
350
|
+
)
|
|
351
|
+
self.warning("%s relocated to fitting position", model_signal["name"])
|
|
352
|
+
else:
|
|
353
|
+
self._update_nvm_signal(nvm_structs_memory_index, nvm_structs_signal_index, model_signal)
|
|
354
|
+
|
|
355
|
+
def _get_memory_area_signal_template(self, memory_area_index):
|
|
356
|
+
memory_area = self.nvm_definitions[memory_area_index]
|
|
357
|
+
signals = memory_area["signals"]
|
|
358
|
+
if signals:
|
|
359
|
+
return signals[0].copy()
|
|
360
|
+
|
|
361
|
+
return {"name": "", "type": "", "x_size": "", "y_size": ""}
|
|
362
|
+
|
|
363
|
+
def _update_nvm_base_struct(self):
|
|
364
|
+
"""Gather and update all nvm signals.
|
|
365
|
+
|
|
366
|
+
1) Updates existing signals,
|
|
367
|
+
2) Deletes/Dummy declares non- and persistent unused signals respectively,
|
|
368
|
+
3) Adds new signals,
|
|
369
|
+
in the nvm struct.
|
|
370
|
+
"""
|
|
371
|
+
|
|
372
|
+
def remove_unused_signals_from_nvm_struct():
|
|
373
|
+
"""Remove unused signals from the nvm struct.
|
|
374
|
+
|
|
375
|
+
The signals are listed in an array and accessed through calculated indices, therefore,
|
|
376
|
+
all unused signals must be removed at once.
|
|
377
|
+
"""
|
|
378
|
+
for mem_area in self._nvm_memory_areas:
|
|
379
|
+
mem_area_index = self._get_nvm_areas_index(mem_area)
|
|
380
|
+
unused_signals_in_area = [
|
|
381
|
+
signal_name
|
|
382
|
+
for signal_name, signal_info in unused_nvm_structs_signals.items()
|
|
383
|
+
if signal_info["memory_area"] == mem_area
|
|
384
|
+
]
|
|
385
|
+
|
|
386
|
+
# Cannot remove signals from the persistent memory areas,
|
|
387
|
+
# however, they can be exchanged for dummy signals
|
|
388
|
+
if "_PER" in self.nvm_definitions[mem_area_index]["name"]:
|
|
389
|
+
for unused_signal_name in unused_signals_in_area:
|
|
390
|
+
if unused_signal_name.startswith("Pos"):
|
|
391
|
+
self.debug("Found unused signal: '%s' in memory area: %s", unused_signal_name, mem_area)
|
|
392
|
+
else:
|
|
393
|
+
self.warning("Found unused signal: '%s' in memory area: %s", unused_signal_name, mem_area)
|
|
394
|
+
self._dummify_nvm_signal(
|
|
395
|
+
mem_area, unused_nvm_structs_signals[unused_signal_name]["signal_index"]
|
|
396
|
+
)
|
|
397
|
+
else:
|
|
398
|
+
self.nvm_definitions[mem_area_index]["signals"] = [
|
|
399
|
+
signal
|
|
400
|
+
for signal in self.nvm_definitions[mem_area_index]["signals"]
|
|
401
|
+
if signal["name"] not in unused_signals_in_area
|
|
402
|
+
]
|
|
403
|
+
|
|
404
|
+
nvm_structs_signals = self._get_signals_in_nvm_structs()
|
|
405
|
+
unused_nvm_structs_signals = self._get_signals_in_nvm_structs()
|
|
406
|
+
new_nvm_structs_signals = []
|
|
407
|
+
|
|
408
|
+
for nvm_memory_area in self._nvm_memory_areas:
|
|
409
|
+
memory_area_index = self._get_nvm_areas_index(nvm_memory_area)
|
|
410
|
+
if "NVM_LIST_CRITICAL" in nvm_memory_area:
|
|
411
|
+
# NVM_LIST_CRITICAL.* only exists in some projects
|
|
412
|
+
continue
|
|
413
|
+
if memory_area_index == -1:
|
|
414
|
+
self.critical("NVM area not found for: %s", nvm_memory_area)
|
|
415
|
+
continue
|
|
416
|
+
for nvm_data_type, nvm_signal_name, nvm_widths in self.nvm_area_iterator(nvm_memory_area):
|
|
417
|
+
nvm_widths = self._clean_values(nvm_widths)
|
|
418
|
+
nvm_signal = self._get_memory_area_signal_template(memory_area_index)
|
|
419
|
+
nvm_signal["name"] = nvm_signal_name
|
|
420
|
+
nvm_signal["type"] = nvm_data_type
|
|
421
|
+
nvm_signal["x_size"] = int(nvm_widths[0])
|
|
422
|
+
nvm_signal["y_size"] = int(nvm_widths[1])
|
|
423
|
+
if nvm_signal_name in nvm_structs_signals:
|
|
424
|
+
self.debug("Deleting %s", nvm_signal_name)
|
|
425
|
+
del unused_nvm_structs_signals[nvm_signal_name]
|
|
426
|
+
self._update_duplicate_nvm_definition(nvm_structs_signals, nvm_signal, nvm_memory_area)
|
|
427
|
+
else:
|
|
428
|
+
new_nvm_structs_signals.append((memory_area_index, nvm_signal["name"], nvm_data_type, nvm_widths))
|
|
429
|
+
remove_unused_signals_from_nvm_struct()
|
|
430
|
+
|
|
431
|
+
for new_signal in new_nvm_structs_signals:
|
|
432
|
+
self._add_signal_to_nvm_struct(*new_signal)
|
|
433
|
+
|
|
434
|
+
def _generate_nvm_structs_updated(self):
|
|
435
|
+
self.info("Start generating updated nvm json file")
|
|
436
|
+
|
|
437
|
+
nvm_structs_updated_path = os.path.abspath(
|
|
438
|
+
os.path.join(self._project_config.get_root_dir(), "output", "nvm_structs_updated.json")
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
self.info("Created %s", nvm_structs_updated_path)
|
|
442
|
+
|
|
443
|
+
with open(nvm_structs_updated_path, "w", encoding="utf-8") as nvm_structs_file:
|
|
444
|
+
json.dump(self.nvm_definitions, nvm_structs_file, indent=4)
|
|
445
|
+
|
|
446
|
+
def _get_struct_and_variable_name(self, memory_area, skip_prefix=False):
|
|
447
|
+
"""Get the name of the memory area struct and variable definitions."""
|
|
448
|
+
prefix = self._project_config.get_scheduler_prefix()
|
|
449
|
+
struct_name = f"{prefix}{memory_area}" if not skip_prefix else memory_area
|
|
450
|
+
if self._project_config.get_code_generation_config("useCamelCaseForNvmVariables"):
|
|
451
|
+
variable_name = "s" + "".join([part[0].upper() + part.lower()[1:] for part in struct_name.split("_")])
|
|
452
|
+
else:
|
|
453
|
+
variable_name = struct_name.lower()
|
|
454
|
+
return struct_name, variable_name
|
|
455
|
+
|
|
456
|
+
def _get_signal_and_struct_defines(self):
|
|
457
|
+
"""Get NVM signal and struct defines."""
|
|
458
|
+
defines = []
|
|
459
|
+
struct_defines = []
|
|
460
|
+
for memory_area in self._nvm_memory_areas:
|
|
461
|
+
struct_name, variable_name = self._get_struct_and_variable_name(memory_area)
|
|
462
|
+
memory_area_index = self._get_nvm_areas_index(memory_area)
|
|
463
|
+
section = self._area_section[memory_area]
|
|
464
|
+
elem_size = self._mem_area_elem_size[memory_area]
|
|
465
|
+
struct_defines.append(f'#include "{section}_START.h"\n')
|
|
466
|
+
struct_defines.append(f"struct {struct_name} {{\n")
|
|
467
|
+
|
|
468
|
+
struct_off = 0
|
|
469
|
+
signals = self.nvm_definitions[memory_area_index]["signals"]
|
|
470
|
+
for signal in signals:
|
|
471
|
+
self._assert_data_type(signal, memory_area)
|
|
472
|
+
struct_defines.append(f' {signal["type"]:7} {self.struct_member_prefix}{signal["name"]}')
|
|
473
|
+
size_string = ""
|
|
474
|
+
size = max(signal["x_size"], 1) * max(signal["y_size"], 1)
|
|
475
|
+
if size > 1:
|
|
476
|
+
if signal["x_size"] > 1:
|
|
477
|
+
size_string += f'[{signal["x_size"]}]'
|
|
478
|
+
if signal["y_size"] > 1:
|
|
479
|
+
if signal["x_size"] < 2:
|
|
480
|
+
self.critical("NVM signal size incorrect. x_size should not be 1 if y_size > 1")
|
|
481
|
+
size_string += "[1]"
|
|
482
|
+
size_string += f'[{signal["y_size"]}]'
|
|
483
|
+
struct_defines.append(size_string)
|
|
484
|
+
struct_defines.append(";\n")
|
|
485
|
+
|
|
486
|
+
if signal["name"] in self._nvm_signals:
|
|
487
|
+
self._nvm_signals[signal["name"]]["struct_off"] = struct_off
|
|
488
|
+
|
|
489
|
+
struct_off += size * byte_size(signal["type"])
|
|
490
|
+
|
|
491
|
+
defines.append(
|
|
492
|
+
"#define "
|
|
493
|
+
f"{signal['name']:40} "
|
|
494
|
+
f"{variable_name}.{self.struct_member_prefix}{signal['name']}\n"
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
max_nr_signals = self.nvm_definitions[memory_area_index]["size"]
|
|
498
|
+
tot_memory = max_nr_signals * elem_size
|
|
499
|
+
free = tot_memory - struct_off
|
|
500
|
+
if free > 0:
|
|
501
|
+
struct_defines.append(
|
|
502
|
+
f' {self.nvm_definitions[memory_area_index]["default_datatype"]} '
|
|
503
|
+
f'unused[{int(free / elem_size)}];\n'
|
|
504
|
+
)
|
|
505
|
+
elif free < 0:
|
|
506
|
+
self.critical("NVM area %s overrun!", self.nvm_definitions[memory_area_index]["name"])
|
|
507
|
+
struct_defines.append(f"}}; /* {struct_off} bytes used of {tot_memory} */\n")
|
|
508
|
+
struct_defines.append(f'#include "{section}_END.h"\n\n')
|
|
509
|
+
|
|
510
|
+
return defines, struct_defines
|
|
511
|
+
|
|
512
|
+
def _generate_nvm_config_headers(self):
|
|
513
|
+
"""Generate nvm config h file."""
|
|
514
|
+
self.info("Start generating nvm header file")
|
|
515
|
+
defines, struct_defines = self._get_signal_and_struct_defines()
|
|
516
|
+
|
|
517
|
+
externals = [f'#include "{self._predecl_start}"\n']
|
|
518
|
+
for area in self._nvm_memory_areas:
|
|
519
|
+
struct_name, variable_name = self._get_struct_and_variable_name(area)
|
|
520
|
+
externals.append(f"extern struct {struct_name} {variable_name};\n")
|
|
521
|
+
externals.append(f'#include "{self._predecl_end}"\n\n')
|
|
522
|
+
|
|
523
|
+
with open(self._file_name + ".h", "w", encoding="utf-8") as hptr:
|
|
524
|
+
hptr.write(self._nvm_header_head)
|
|
525
|
+
hptr.writelines(struct_defines)
|
|
526
|
+
hptr.writelines(externals)
|
|
527
|
+
hptr.write("\n")
|
|
528
|
+
hptr.writelines(defines)
|
|
529
|
+
hptr.write(self._nvm_header_footer)
|
|
530
|
+
|
|
531
|
+
def _generate_nvm_config_source(self):
|
|
532
|
+
"""Generate the c-file containing the NVM definition."""
|
|
533
|
+
# TODO: Add memory from previous builds!!! and mark old positions #
|
|
534
|
+
self.info("Start generating nvm source file")
|
|
535
|
+
with open(self._file_name + ".c", "w", encoding="utf-8") as cptr:
|
|
536
|
+
cptr.write(f'#include "{self._nvm_defs["fileName"]}.h"\n\n')
|
|
537
|
+
for area, pragma in zip(self._nvm_memory_areas, self._mem_area_pragmas):
|
|
538
|
+
struct_name, variable_name = self._get_struct_and_variable_name(area)
|
|
539
|
+
cptr.write(f'#include "{pragma[0]}"\n')
|
|
540
|
+
cptr.write(f"struct {struct_name} {variable_name};\n")
|
|
541
|
+
cptr.write(f'#include "{pragma[1]}"\n\n')
|
|
542
|
+
|
|
543
|
+
def _generate_nvm_config_a2l(self):
|
|
544
|
+
"""Generate the a2l-file describing the NVM definition."""
|
|
545
|
+
self.info("Start generating nvm a2l file")
|
|
546
|
+
a2l_dict = self._a2l_dict()
|
|
547
|
+
a2l = A2l(a2l_dict, self._project_config)
|
|
548
|
+
a2l.gen_a2l(self._file_name + ".a2l")
|
|
549
|
+
|
|
550
|
+
def generate_nvm_config_files(self, no_nvm_a2l):
|
|
551
|
+
"""Generate all files for variables in the NVM definition.
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
no_nvm_a2l (bool): Do not generate a2l file.
|
|
555
|
+
"""
|
|
556
|
+
self._update_nvm_base_struct()
|
|
557
|
+
self._generate_nvm_structs_updated()
|
|
558
|
+
self._generate_nvm_config_headers()
|
|
559
|
+
self._generate_nvm_config_source()
|
|
560
|
+
if not no_nvm_a2l:
|
|
561
|
+
self._generate_nvm_config_a2l()
|
|
562
|
+
|
|
563
|
+
@staticmethod
|
|
564
|
+
def _get_signal_list(signals):
|
|
565
|
+
return signals if isinstance(signals, list) else [signals]
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
class ZCNVMDef(NVMDef):
|
|
569
|
+
"""A class for handling of ZC NVM definitions."""
|
|
570
|
+
|
|
571
|
+
def __init__(self, project_config, unit_cfg, nvm_vars):
|
|
572
|
+
"""Init.
|
|
573
|
+
|
|
574
|
+
Args:
|
|
575
|
+
project_config (BuildProjConfig): current project configuration.
|
|
576
|
+
unit_cfg (UnitConfigs): Unit configurations.
|
|
577
|
+
nvm_vars (dict): NVM variables from unit configurations.
|
|
578
|
+
"""
|
|
579
|
+
super().__init__(project_config, unit_cfg, nvm_vars)
|
|
580
|
+
self.struct_member_prefix = "e_"
|
|
581
|
+
self._valid_nvm_definitions = None
|
|
582
|
+
self._update_nvm_base_struct()
|
|
583
|
+
prefix = self._project_config.get_scheduler_prefix()
|
|
584
|
+
self.project_nvm_definitions = {
|
|
585
|
+
f"{prefix}{item['name']}": item for item in self.nvm_definitions
|
|
586
|
+
}
|
|
587
|
+
self._predecl_start = bd.PREDECL_NVM_START
|
|
588
|
+
self._predecl_end = bd.PREDECL_NVM_END
|
|
589
|
+
self.init_function = f"void {prefix}VcNvmInit(void)"
|
|
590
|
+
self.main_function = f"void {prefix}VcNvm(void)"
|
|
591
|
+
|
|
592
|
+
@property
|
|
593
|
+
def valid_nvm_definitions(self):
|
|
594
|
+
"""Get the valid NVM definitions."""
|
|
595
|
+
return self._valid_nvm_definitions
|
|
596
|
+
|
|
597
|
+
@valid_nvm_definitions.setter
|
|
598
|
+
def valid_nvm_definitions(self, yaml_nvm_definitions):
|
|
599
|
+
"""Return a set of NVM definitions appearing in both the project and the project yaml file.
|
|
600
|
+
|
|
601
|
+
Args:
|
|
602
|
+
yaml_nvm_definitions (dict): NVM lists listed in the NVM configuration yaml file.
|
|
603
|
+
Returns:
|
|
604
|
+
valid_nvm_definitions (dict): Validated NVM definitions,
|
|
605
|
+
listed in both NVM configuration yaml file as well as project.
|
|
606
|
+
"""
|
|
607
|
+
local_yaml_nvm_definitions = deepcopy(yaml_nvm_definitions)
|
|
608
|
+
nvms_not_in_project = set(local_yaml_nvm_definitions.keys()) - set(self.project_nvm_definitions.keys())
|
|
609
|
+
nvms_not_in_yaml = set(self.project_nvm_definitions.keys()) - set(local_yaml_nvm_definitions.keys())
|
|
610
|
+
for key in nvms_not_in_project:
|
|
611
|
+
self.warning(f'Ignoring NVM definition {key} since it does not appear in nvm_structs.json.')
|
|
612
|
+
del local_yaml_nvm_definitions[key]
|
|
613
|
+
for key in nvms_not_in_yaml:
|
|
614
|
+
self.warning(f'Ignoring NVM definition {key} since it does not appear in the project NVM yaml file.')
|
|
615
|
+
self._valid_nvm_definitions = local_yaml_nvm_definitions
|
|
616
|
+
|
|
617
|
+
def _update_header_and_footer(self):
|
|
618
|
+
name = self._project_config.get_composition_config("softwareComponentName")
|
|
619
|
+
use_rte_nvm_structs = self._project_config.get_code_generation_config("useRteNvmStructs")
|
|
620
|
+
self._nvm_header_head += f'#include "Rte_{name}.h"\n'
|
|
621
|
+
if use_rte_nvm_structs:
|
|
622
|
+
self._nvm_header_head += '#include "Rte_Type.h"\n\n'
|
|
623
|
+
self._nvm_header_footer = (
|
|
624
|
+
"\n"
|
|
625
|
+
f'#include "{bd.PREDECL_CODE_ASIL_D_START}"\n'
|
|
626
|
+
f"{self.init_function};\n"
|
|
627
|
+
f"{self.main_function};\n"
|
|
628
|
+
f'#include "{bd.PREDECL_CODE_ASIL_D_END}"\n'
|
|
629
|
+
f"{self._nvm_header_footer}"
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
def _generate_rte_type_nvm_config_headers(self):
|
|
633
|
+
"""Generate NVM config header file using RTE struct definitions."""
|
|
634
|
+
self.info("Start generating nvm header file")
|
|
635
|
+
defines = self._get_signal_and_struct_defines()[0]
|
|
636
|
+
externals = [f'#include "{self._predecl_start}"\n']
|
|
637
|
+
for area in self.valid_nvm_definitions.keys():
|
|
638
|
+
struct_name, variable_name = self._get_struct_and_variable_name(area, skip_prefix=True)
|
|
639
|
+
externals.append(f"extern dt_{struct_name} {variable_name};\n")
|
|
640
|
+
externals.append(f'#include "{self._predecl_end}"\n\n')
|
|
641
|
+
with open(self._file_name + ".h", "w", encoding="utf-8") as hptr:
|
|
642
|
+
hptr.write(self._nvm_header_head)
|
|
643
|
+
hptr.writelines(externals)
|
|
644
|
+
hptr.writelines(defines)
|
|
645
|
+
hptr.write(self._nvm_header_footer)
|
|
646
|
+
|
|
647
|
+
def _generate_rte_type_nvm_config_source(self):
|
|
648
|
+
"""Generate the c-file containing the NVM definition using RTE struct definitions."""
|
|
649
|
+
# TODO: Add memory from previous builds!!! and mark old positions #
|
|
650
|
+
self.info("Start generating nvm source file")
|
|
651
|
+
with open(self._file_name + ".c", "w", encoding="utf-8") as cptr:
|
|
652
|
+
cptr.write(f'#include "{self._nvm_defs["fileName"]}.h"\n\n')
|
|
653
|
+
for area, pragma in zip(self._nvm_memory_areas, self._mem_area_pragmas):
|
|
654
|
+
struct_name, variable_name = self._get_struct_and_variable_name(area)
|
|
655
|
+
if struct_name in self.valid_nvm_definitions:
|
|
656
|
+
cptr.write(f'#include "{pragma[0]}"\n')
|
|
657
|
+
cptr.write(f"dt_{struct_name} {variable_name};\n")
|
|
658
|
+
cptr.write(f'#include "{pragma[1]}"\n\n')
|
|
659
|
+
|
|
660
|
+
def _append_nvm_rte_function_calls(self):
|
|
661
|
+
"""Append the NVM RTE function calls to the NVM config source file."""
|
|
662
|
+
init_function_lines = [
|
|
663
|
+
f'#include "{bd.CVC_CODE_ASIL_D_START}"\n'
|
|
664
|
+
f"{self.init_function} {{\n",
|
|
665
|
+
" //Call this function in the SWC init runnable\n"
|
|
666
|
+
]
|
|
667
|
+
main_function = [
|
|
668
|
+
f'#include "{bd.CVC_CODE_ASIL_D_START}"\n'
|
|
669
|
+
f"{self.main_function} {{\n",
|
|
670
|
+
" //Call this function in the SWC main runnable\n",
|
|
671
|
+
]
|
|
672
|
+
footer = [
|
|
673
|
+
"}\n",
|
|
674
|
+
f'#include "{bd.CVC_CODE_ASIL_D_END}"\n',
|
|
675
|
+
]
|
|
676
|
+
|
|
677
|
+
main_function_lines = []
|
|
678
|
+
|
|
679
|
+
for nvm_name, nvm_data in self.valid_nvm_definitions.items():
|
|
680
|
+
if nvm_data["type"] not in ["type1", "type2"]:
|
|
681
|
+
self.critical(f"Unknown NVM type: {nvm_data['type']} for NVM: {nvm_name}")
|
|
682
|
+
continue
|
|
683
|
+
if nvm_data["method"] not in ["DIRECT-CALL", "NVSWCOMPONENT"]:
|
|
684
|
+
self.critical(f"Unknown NVM method: {nvm_data['method']} for NVM: {nvm_name}")
|
|
685
|
+
continue
|
|
686
|
+
|
|
687
|
+
if nvm_data["type"] == "type2":
|
|
688
|
+
self.warning(
|
|
689
|
+
f'{nvm_name} is a type2 {nvm_data["method"]}. Due to inherent risk type2 write calls are '
|
|
690
|
+
'not generated automatically, they have to be written manually and added to source code.'
|
|
691
|
+
)
|
|
692
|
+
main_function_lines.append(
|
|
693
|
+
f" // Nvm {nvm_name} is type 2, add call in manually written source code.\n"
|
|
694
|
+
)
|
|
695
|
+
elif nvm_data["type"] == "type1":
|
|
696
|
+
variable_name = self._get_struct_and_variable_name(nvm_name, skip_prefix=True)[1]
|
|
697
|
+
if nvm_data["method"] == "DIRECT-CALL":
|
|
698
|
+
pim_call = f"Rte_Pim_{nvm_name}()"
|
|
699
|
+
main_function_lines.append(f" *{pim_call} = {variable_name};\n")
|
|
700
|
+
init_function_lines.append(f" {variable_name} = *{pim_call};\n")
|
|
701
|
+
elif nvm_data["method"] == "NVSWCOMPONENT":
|
|
702
|
+
init_function_lines.append(
|
|
703
|
+
f" Rte_Read_{nvm_name.upper()}_{nvm_name.upper()}(&{variable_name});\n"
|
|
704
|
+
)
|
|
705
|
+
main_function.append(
|
|
706
|
+
f" Rte_Write_{nvm_name.upper()}_{nvm_name.upper()}(&{variable_name});\n"
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
output = init_function_lines + footer + ["\n"] + main_function + main_function_lines + footer
|
|
710
|
+
with open(self._file_name + ".c", mode="a", encoding="utf-8") as cptr:
|
|
711
|
+
cptr.writelines(output)
|
|
712
|
+
|
|
713
|
+
def generate_nvm_rte_files(self):
|
|
714
|
+
"""Generate the NVM RTE files."""
|
|
715
|
+
if self.valid_nvm_definitions is None:
|
|
716
|
+
self.critical('Valid NVM definitions not set. Cannot generate NVM RTE files.')
|
|
717
|
+
return
|
|
718
|
+
|
|
719
|
+
use_rte_nvm_structs = self._project_config.get_code_generation_config("useRteNvmStructs")
|
|
720
|
+
|
|
721
|
+
self._update_header_and_footer()
|
|
722
|
+
self._generate_nvm_structs_updated()
|
|
723
|
+
if use_rte_nvm_structs:
|
|
724
|
+
self._generate_rte_type_nvm_config_headers()
|
|
725
|
+
self._generate_rte_type_nvm_config_source()
|
|
726
|
+
else:
|
|
727
|
+
self._generate_nvm_config_headers()
|
|
728
|
+
self._generate_nvm_config_source()
|
|
729
|
+
self._append_nvm_rte_function_calls()
|