199 lines
8.7 KiB
Python
199 lines
8.7 KiB
Python
# Copyright 2024 Volvo Car Corporation
|
|
# Licensed under Apache 2.0.
|
|
|
|
# -*- coding: utf-8 -*-
|
|
"""Module containing cvc classes for VCC - defines and includes for memory sections."""
|
|
|
|
import time
|
|
from pathlib import Path
|
|
from powertrain_build import build_defs
|
|
from powertrain_build.problem_logger import ProblemLogger
|
|
|
|
|
|
class MemorySection(ProblemLogger):
|
|
"""Handle headers for CVC_* definitions."""
|
|
|
|
calibration_definitions = [
|
|
'CVC_CAL',
|
|
'CVC_CAL_ASIL_A',
|
|
'CVC_CAL_ASIL_B',
|
|
'CVC_CAL_ASIL_C',
|
|
'CVC_CAL_ASIL_D',
|
|
'CVC_CAL_MERGEABLE_ASIL_A',
|
|
'CVC_CAL_MERGEABLE_ASIL_B',
|
|
'CVC_CAL_MERGEABLE_ASIL_C',
|
|
'CVC_CAL_MERGEABLE_ASIL_D'
|
|
]
|
|
measurable_definitions = [
|
|
'CVC_DISP',
|
|
'CVC_DISP_ASIL_A',
|
|
'CVC_DISP_ASIL_B',
|
|
'CVC_DISP_ASIL_C',
|
|
'CVC_DISP_ASIL_D'
|
|
]
|
|
|
|
def __init__(self, build_cfg):
|
|
super().__init__()
|
|
self.build_cfg = build_cfg
|
|
self.mem_map_config = self.build_cfg.get_memory_map_config()
|
|
self.include_header_guards = self.mem_map_config['includeHeaderGuards']
|
|
self.mem_map_include = f'#include "{self.mem_map_config["memMapPrefix"]}_MemMap.h"\n'
|
|
self.xcp_enabled = self.build_cfg.get_xcp_enabled()
|
|
self.use_volatile_globals = self.build_cfg.get_use_volatile_globals()
|
|
|
|
@staticmethod
|
|
def _get_mem_map_section(section):
|
|
return 'STOP' if section == 'END' else section
|
|
|
|
@staticmethod
|
|
def _get_header(section_file):
|
|
section_file_header_guard = section_file.split('.')[0].upper()
|
|
return [
|
|
f'#ifndef {section_file_header_guard}_H\n',
|
|
f'#define {section_file_header_guard}_H\n\n'
|
|
]
|
|
|
|
@staticmethod
|
|
def _get_footer(section_file):
|
|
section_file_header_guard = section_file.split('.')[0].upper()
|
|
return [f'\n#endif /* {section_file_header_guard}_H */\n']
|
|
|
|
def _get_cal(self, section):
|
|
cvc_undefines = [f'#undef {definition}\n' for definition in self.calibration_definitions]
|
|
if section == 'START':
|
|
volatile_string = 'volatile' if self.use_volatile_globals else ''
|
|
cvc_defines = [f'#define {definition} {volatile_string}\n' for definition in self.calibration_definitions]
|
|
else:
|
|
cvc_defines = []
|
|
section_type = 'cal' if self.xcp_enabled else 'disp'
|
|
memory_section_handling = [
|
|
self.mem_map_config['projectDefines'][self._get_mem_map_section(section)][section_type] + '\n'
|
|
]
|
|
if self.mem_map_config['includeMemMapForCalibration'] or not self.xcp_enabled:
|
|
memory_section_handling.append(self.mem_map_include)
|
|
return cvc_undefines, cvc_defines, memory_section_handling
|
|
|
|
def _get_disp(self, section):
|
|
cvc_undefines = [f'#undef {definition}\n' for definition in self.measurable_definitions]
|
|
if section == 'START':
|
|
volatile_string = 'volatile' if self.use_volatile_globals else ''
|
|
cvc_defines = [f'#define {definition} {volatile_string}\n' for definition in self.measurable_definitions]
|
|
else:
|
|
cvc_defines = []
|
|
memory_section_handling = [
|
|
self.mem_map_config['projectDefines'][self._get_mem_map_section(section)]['disp'] + '\n',
|
|
self.mem_map_include
|
|
]
|
|
return cvc_undefines, cvc_defines, memory_section_handling
|
|
|
|
def _get_code(self, section):
|
|
cvc_undefines = []
|
|
cvc_defines = []
|
|
memory_section_handling = [
|
|
self.mem_map_config['projectDefines'][self._get_mem_map_section(section)]['code'] + '\n',
|
|
self.mem_map_include
|
|
]
|
|
return cvc_undefines, cvc_defines, memory_section_handling
|
|
|
|
def _get_const(self, section):
|
|
cvc_undefines = []
|
|
cvc_defines = []
|
|
memory_section_handling = [
|
|
self.mem_map_config['projectDefines'][self._get_mem_map_section(section)]['const'] + '\n',
|
|
self.mem_map_include
|
|
]
|
|
return cvc_undefines, cvc_defines, memory_section_handling
|
|
|
|
def _get_nvm(self, section):
|
|
cvc_undefines = []
|
|
cvc_defines = []
|
|
memory_section_handling = [
|
|
self.mem_map_config['projectDefines'][self._get_mem_map_section(section)]['nvm'] + '\n',
|
|
self.mem_map_include
|
|
]
|
|
return cvc_undefines, cvc_defines, memory_section_handling
|
|
|
|
def _get_rest(self):
|
|
cvc_undefines = []
|
|
cvc_defines = []
|
|
memory_section_handling = [
|
|
self.mem_map_include
|
|
]
|
|
return cvc_undefines, cvc_defines, memory_section_handling
|
|
|
|
def _get_predecl(self):
|
|
cvc_undefines = []
|
|
cvc_defines = []
|
|
memory_section_handling = [
|
|
self.mem_map_include
|
|
]
|
|
return cvc_undefines, cvc_defines, memory_section_handling
|
|
|
|
def generate_cvc_header(self, section, section_file):
|
|
"""Generate CVC headers.
|
|
|
|
Args:
|
|
section (str): Name of the CVC section
|
|
section_file (str): Name of the header file
|
|
Returns:
|
|
lines_to_write (list(str)): Lines to write to given section file.
|
|
"""
|
|
header = self._get_header(section_file) if self.include_header_guards else []
|
|
footer = self._get_footer(section_file) if self.include_header_guards else []
|
|
if '_CAL_' in section_file:
|
|
cvc_undefines, cvc_defines, memory_section_handling = self._get_cal(section)
|
|
elif '_DISP_' in section_file:
|
|
cvc_undefines, cvc_defines, memory_section_handling = self._get_disp(section)
|
|
elif not section_file.startswith('PREDECL_'):
|
|
if section_file.startswith('CVC_CAL') or section_file.startswith('CVC_DISP'):
|
|
self.critical('Should not find CVC_CAL/DISP here. Check logic. File: %s.', section_file)
|
|
elif section_file.startswith('CVC_CODE'):
|
|
cvc_undefines, cvc_defines, memory_section_handling = self._get_code(section)
|
|
elif section_file.startswith('CVC_CONST'):
|
|
cvc_undefines, cvc_defines, memory_section_handling = self._get_const(section)
|
|
else:
|
|
cvc_undefines, cvc_defines, memory_section_handling = self._get_rest()
|
|
else:
|
|
cvc_undefines, cvc_defines, memory_section_handling = self._get_predecl()
|
|
|
|
return header + cvc_undefines + cvc_defines + memory_section_handling + footer
|
|
|
|
def generate_required_header_files(self):
|
|
"""Generate required header files to delivery folder.
|
|
|
|
Generate required header files such as memory protection files.
|
|
NOTE: Currently, only one ASIL level can be selected for an SWC.
|
|
"""
|
|
self.info('******************************************************')
|
|
self.info('Start generating required header files')
|
|
start_time = time.time()
|
|
src_dst_dir = self.build_cfg.get_src_code_dst_dir()
|
|
for section_dict in build_defs.PREDECL_EXTRA.values():
|
|
for section_file in section_dict.values():
|
|
header = self._get_header(section_file) if self.include_header_guards else []
|
|
footer = self._get_footer(section_file) if self.include_header_guards else []
|
|
with Path(src_dst_dir, section_file).open('w', encoding="utf-8") as header_file_handler:
|
|
header_file_handler.writelines(header + footer)
|
|
|
|
for asil_dict in build_defs.ASIL_LEVEL_MAP.values():
|
|
for type_dict in asil_dict.values():
|
|
for section_dict in type_dict.values():
|
|
for section, section_file in section_dict.items():
|
|
lines_to_write = self.generate_cvc_header(section, section_file)
|
|
with Path(src_dst_dir, section_file).open('w', encoding="utf-8") as header_file_handler:
|
|
header_file_handler.writelines(lines_to_write)
|
|
|
|
for nvm_type, nvm_dict in build_defs.NVM_LEVEL_MAP.items():
|
|
for section_dict in nvm_dict.values():
|
|
for section, section_file in section_dict.items():
|
|
section_config = self.mem_map_config['projectDefines'][self._get_mem_map_section(section)]
|
|
if nvm_type == "NORMAL" and "nvm" in section_config:
|
|
lines_to_write = self._get_nvm(section)[2]
|
|
else:
|
|
lines_to_write = []
|
|
header = self._get_header(section_file) if self.include_header_guards else []
|
|
footer = self._get_footer(section_file) if self.include_header_guards else []
|
|
with Path(src_dst_dir, section_file).open('w', encoding="utf-8") as header_file_handler:
|
|
header_file_handler.writelines(header + lines_to_write + footer)
|
|
self.info('Finished generating required header files (in %4.2f s)', time.time() - start_time)
|