Clone of official tools

Revision:
43:2a7da56ebd24
Parent:
41:2a77626a4c21
--- a/export/uvision/__init__.py	Mon Nov 06 13:17:14 2017 -0600
+++ b/export/uvision/__init__.py	Tue Sep 25 13:43:09 2018 -0500
@@ -1,5 +1,8 @@
+from __future__ import print_function, absolute_import
+from builtins import str
+
 import os
-from os.path import sep, normpath, join, exists
+from os.path import normpath, exists, dirname
 import ntpath
 import copy
 from collections import namedtuple
@@ -7,13 +10,11 @@
 from subprocess import Popen, PIPE
 import re
 
-from tools.arm_pack_manager import Cache
+from tools.resources import FileType
 from tools.targets import TARGET_MAP
-from tools.export.exporters import Exporter, apply_supported_whitelist
+from tools.export.exporters import Exporter
 from tools.export.cmsis import DeviceCMSIS
 
-cache_d = False
-
 
 class DeviceUvision(DeviceCMSIS):
     """Uvision Device class, inherits CMSIS Device class
@@ -31,19 +32,23 @@
 
     def uv_debug(self):
         """Return a namedtuple of information about uvision debug settings"""
-        UVDebug = namedtuple('UVDebug',['bin_loc','core_flag', 'key'])
+        UVDebug = namedtuple('UVDebug', ['bin_loc', 'core_flag', 'key'])
 
         # CortexMXn => pCMX
         cpu = self.core.replace("Cortex-", "C")
         cpu = cpu.replace("+", "")
         cpu = cpu.replace("F", "")
+        cpu = cpu.replace("-NS", "")
         cpu_flag = "p"+cpu
 
         # Locations found in Keil_v5/TOOLS.INI
-        debuggers = {"st-link": ('STLink\\ST-LINKIII-KEIL_SWO.dll', 'ST-LINKIII-KEIL_SWO'),
-                     "j-link":('Segger\\JL2CM3.dll', 'JL2CM3'),
-                     "cmsis-dap":('BIN\\CMSIS_AGDI.dll', 'CMSIS_AGDI'),
-                     "nulink":('NULink\\Nu_Link.dll','Nu_Link')}
+        debuggers = {
+            "st-link": ('STLink\\ST-LINKIII-KEIL_SWO.dll',
+                        'ST-LINKIII-KEIL_SWO'),
+            "j-link": ('Segger\\JL2CM3.dll', 'JL2CM3'),
+            "cmsis-dap": ('BIN\\CMSIS_AGDI.dll', 'CMSIS_AGDI'),
+            "nulink": ('NULink\\Nu_Link.dll', 'Nu_Link')
+        }
         res = debuggers[self.debug.lower()]
         binary = res[0]
         key = res[1]
@@ -55,7 +60,7 @@
         S = SW/JTAG Clock ID
         C = CPU index in JTAG chain
         P = Access Port
-        For the Options for Target -> Debug tab -> settings -> "Flash" tab in the dialog:
+        For the Options for Target -> Debug -> settings -> "Flash" dialog:
         FD = RAM Start for Flash Functions
         FC = RAM Size for Flash Functions
         FN = Number of Flash types
@@ -64,44 +69,55 @@
         FL = Size of the Flash Device
         FP = Full path to the Device algorithm (RTE)
 
-        Necessary to flash some targets. Info gathered from algorithms field of pdsc file.
+        Necessary to flash some targets.
         '''
         fl_count = 0
+
         def get_mem_no_x(mem_str):
             mem_reg = "\dx(\w+)"
             m = re.search(mem_reg, mem_str)
             return m.group(1) if m else None
 
-        RAMS = [(get_mem_no_x(info["start"]), get_mem_no_x(info["size"]))
-                for mem, info in self.target_info["memory"].items() if "RAM" in mem]
-        format_str = "UL2CM3(-S0 -C0 -P0 -FD{ramstart}"+" -FC{ramsize} "+"-FN{num_algos} {extra_flags})"
+        RAMS = [
+            (get_mem_no_x(info["start"]), get_mem_no_x(info["size"]))
+            for mem, info in self.target_info["memory"].items() if "RAM" in mem
+        ]
+        format_str = (
+            "UL2CM3(-S0 -C0 -P0 -FD{ramstart}"
+            " -FC{ramsize} -FN{num_algos} {extra_flags})"
+        )
         ramstart = ''
-        #Default according to Keil developer
+        # Default according to Keil developer
         ramsize = '1000'
-        if len(RAMS)>=1:
+        if len(RAMS) >= 1:
             ramstart = RAMS[0][0]
         extra_flags = []
         for name, info in self.target_info["algorithm"].items():
             if not name or not info:
                 continue
-            if int(info["default"])==0:
+            if int(info["default"]) == 0:
                 continue
             name_reg = "\w*/([\w_]+)\.flm"
             m = re.search(name_reg, name.lower())
             fl_name = m.group(1) if m else None
             name_flag = "-FF" + str(fl_count) + fl_name
 
-            start, size = get_mem_no_x(info["start"]), get_mem_no_x(info["size"])
-            rom_start_flag = "-FS"+str(fl_count)+str(start)
+            start = get_mem_no_x(info["start"])
+            size = get_mem_no_x(info["size"])
+            rom_start_flag = "-FS" + str(fl_count) + str(start)
             rom_size_flag = "-FL" + str(fl_count) + str(size)
 
             if info["ramstart"] is not None and info["ramsize"] is not None:
                 ramstart = get_mem_no_x(info["ramstart"])
                 ramsize = get_mem_no_x(info["ramsize"])
 
-            path_flag = "-FP" + str(fl_count) + "($$Device:"+self.dname+"$"+name+")"
+            path_flag = "-FP{}($$Device:{}${})".format(
+                str(fl_count), self.dname, name
+            )
 
-            extra_flags.extend([name_flag, rom_start_flag, rom_size_flag, path_flag])
+            extra_flags.extend([
+                name_flag, rom_start_flag, rom_size_flag, path_flag
+            ])
             fl_count += 1
 
         extra = " ".join(extra_flags)
@@ -117,8 +133,6 @@
     project file (.uvprojx).
     The needed information can be viewed in uvision.tmpl
     """
-    NAME = 'uvision5'
-    TOOLCHAIN = 'ARM'
 
     POST_BINARY_WHITELIST = set([
         "MCU_NRF51Code.binary_hook",
@@ -130,14 +144,7 @@
         "NCS36510TargetCode.ncs36510_addfib"
     ])
 
-    @classmethod
-    def is_target_supported(cls, target_name):
-        target = TARGET_MAP[target_name]
-        return apply_supported_whitelist(
-            cls.TOOLCHAIN, cls.POST_BINARY_WHITELIST, target) and\
-            DeviceCMSIS.check_supported(target_name)
-
-    #File associations within .uvprojx file
+    # File associations within .uvprojx file
     file_types = {'.cpp': 8, '.c': 1, '.s': 2,
                   '.obj': 3, '.o': 3, '.lib': 4,
                   '.ar': 4, '.h': 5, '.hpp': 5, '.sct': 4}
@@ -155,8 +162,8 @@
         </File>
         """
         for loc in files:
-            #Encapsulates the information necessary for template entry above
-            UVFile = namedtuple('UVFile', ['type','loc','name'])
+            # Encapsulates the information necessary for template entry above
+            UVFile = namedtuple('UVFile', ['type', 'loc', 'name'])
             _, ext = os.path.splitext(loc)
             if ext.lower() in self.file_types:
                 type = self.file_types[ext.lower()]
@@ -166,22 +173,40 @@
     def format_flags(self):
         """Format toolchain flags for Uvision"""
         flags = copy.deepcopy(self.flags)
-        # to be preprocessed with armcc
         asm_flag_string = (
             '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' +
-            ",".join(filter(lambda f: f.startswith("-D"), flags['asm_flags'])))
+            ",".join("-D{}".format(s) for s in
+                     self.toolchain.get_symbols(for_asm=True)))
         flags['asm_flags'] = asm_flag_string
-        # All non-asm flags are in one template field
-        c_flags = list(set(flags['c_flags'] + flags['cxx_flags'] +flags['common_flags']))
-        ld_flags = list(set(flags['ld_flags'] ))
-        # These flags are in template to be set by user i n IDE
-        template = ["--no_vla", "--cpp", "--c99"]
-        # Flag is invalid if set in template
-        # Optimizations are also set in the template
-        invalid_flag = lambda x: x in template or re.match("-O(\d|time)", x) 
-        flags['c_flags'] = [flag.replace('"','\\"') for flag in c_flags if not invalid_flag(flag)]
-        flags['c_flags'] = " ".join(flags['c_flags'])
-        flags['ld_flags'] = " ".join(flags['ld_flags'])
+
+        config_header = self.config_header_ref
+        config_option = self.toolchain.get_config_option(config_header.name)
+        c_flags = set(
+            flags['c_flags'] + flags['cxx_flags'] + flags['common_flags']
+        )
+        in_template = set(
+            ["--no_vla", "--cpp", "--c99", "-MMD"] + config_option
+        )
+
+        def valid_flag(x):
+            return (
+                x not in in_template and
+                not x.startswith("-O") and
+                not x.startswith("-std") and
+                not x.startswith("-D")
+            )
+
+        def is_define(s):
+            return s.startswith("-D") and "(" not in s
+
+        flags['c_flags'] = " ".join(
+            f.replace('"', '\\"') for f in c_flags if valid_flag(f)
+        )
+        flags['c_flags'] += " "
+        flags['c_flags'] += " ".join(config_option)
+        flags['c_defines'] = " ".join(f[2:].replace('"', '\\"')
+                                      for f in c_flags if is_define(f))
+        flags['ld_flags'] = " ".join(set(flags['ld_flags']))
         return flags
 
     def format_src(self, srcs):
@@ -189,7 +214,7 @@
         grouped = self.group_project_files(srcs)
         for group, files in grouped.items():
             grouped[group] = sorted(list(self.uv_files(files)),
-                                    key=lambda (_, __, name): name.lower())
+                                    key=lambda tuple: tuple[2].lower())
         return grouped
 
     @staticmethod
@@ -204,38 +229,54 @@
 
     def generate(self):
         """Generate the .uvproj file"""
-        cache = Cache(True, False)
-        if cache_d:
-            cache.cache_descriptors()
-
-        srcs = self.resources.headers + self.resources.s_sources + \
-               self.resources.c_sources + self.resources.cpp_sources + \
-               self.resources.objects + self.resources.libraries
+        srcs = (
+            self.resources.headers + self.resources.s_sources +
+            self.resources.c_sources + self.resources.cpp_sources +
+            self.resources.objects + self.libraries
+        )
         ctx = {
             'name': self.project_name,
             # project_files => dict of generators - file group to generator of
             # UVFile tuples defined above
-            'project_files': sorted(list(self.format_src(srcs).iteritems()),
-                                    key=lambda (group, _): group.lower()),
-            'linker_script':self.toolchain.correct_scatter_shebang(
-                self.resources.linker_script),
-            'include_paths': '; '.join(self.resources.inc_dirs).encode('utf-8'),
+            'project_files': sorted(list(self.format_src(srcs).items()),
+                                    key=lambda tuple: tuple[0].lower()),
+            'include_paths': ';'.join(self.filter_dot(d) for d in
+                                      self.resources.inc_dirs).encode('utf-8'),
             'device': DeviceUvision(self.target),
         }
-        if ctx['linker_script'] is not self.resources.linker_script:
+        sct_name, sct_path = self.resources.get_file_refs(
+            FileType.LD_SCRIPT)[0]
+        ctx['linker_script'] = self.toolchain.correct_scatter_shebang(
+            sct_path, dirname(sct_name))
+        if ctx['linker_script'] != sct_path:
             self.generated_files.append(ctx['linker_script'])
-        core = ctx['device'].core
-        ctx['cputype'] = core.rstrip("FD")
-        if core.endswith("FD"):
+        ctx['cputype'] = ctx['device'].core.rstrip("FD").replace("-NS", "")
+        if ctx['device'].core.endswith("FD"):
             ctx['fpu_setting'] = 3
-        elif core.endswith("F"):
+        elif ctx['device'].core.endswith("F"):
             ctx['fpu_setting'] = 2
         else:
             ctx['fpu_setting'] = 1
-        ctx['fputype'] = self.format_fpu(core)
+        ctx['fputype'] = self.format_fpu(ctx['device'].core)
+        ctx['armc6'] = int(self.TOOLCHAIN is 'ARMC6')
+        ctx['toolchain_name'] = self.TOOLCHAIN_NAME
         ctx.update(self.format_flags())
-        self.gen_file('uvision/uvision.tmpl', ctx, self.project_name+".uvprojx")
-        self.gen_file('uvision/uvision_debug.tmpl', ctx, self.project_name + ".uvoptx")
+        self.gen_file(
+            'uvision/uvision.tmpl', ctx, self.project_name + ".uvprojx"
+        )
+        self.gen_file(
+            'uvision/uvision_debug.tmpl', ctx, self.project_name + ".uvoptx"
+        )
+
+    @staticmethod
+    def clean(project_name):
+        os.remove(project_name + ".uvprojx")
+        os.remove(project_name + ".uvoptx")
+        # legacy .build directory cleaned if exists
+        if exists('.build'):
+            shutil.rmtree('.build')
+        if exists('BUILD'):
+            shutil.rmtree('BUILD')
 
     @staticmethod
     def build(project_name, log_name='build_log.txt', cleanup=True):
@@ -251,18 +292,12 @@
 
         # Print the log file to stdout
         with open(log_name, 'r') as f:
-            print f.read()
+            print(f.read())
 
         # Cleanup the exported and built files
         if cleanup:
             os.remove(log_name)
-            os.remove(project_name+".uvprojx")
-            os.remove(project_name+".uvoptx")
-            # legacy .build directory cleaned if exists
-            if exists('.build'):
-                shutil.rmtree('.build')
-            if exists('BUILD'):
-                shutil.rmtree('BUILD')
+            Uvision.clean(project_name)
 
         # Returns 0 upon success, 1 upon a warning, and neither upon an error
         if ret_code != 0 and ret_code != 1:
@@ -270,3 +305,49 @@
             return -1
         else:
             return 0
+
+
+class UvisionArmc5(Uvision):
+    NAME = 'uvision5-armc5'
+    TOOLCHAIN = 'ARM'
+    TOOLCHAIN_NAME = ''
+
+    @classmethod
+    def is_target_supported(cls, target_name):
+        target = TARGET_MAP[target_name]
+        if not (set(target.supported_toolchains).intersection(
+                set(["ARM", "uARM"]))):
+            return False
+        if not DeviceCMSIS.check_supported(target_name):
+            return False
+        if "Cortex-A" in target.core:
+            return False
+        if not hasattr(target, "post_binary_hook"):
+            return True
+        if target.post_binary_hook['function'] in cls.POST_BINARY_WHITELIST:
+            return True
+        else:
+            return False
+
+
+class UvisionArmc6(Uvision):
+    NAME = 'uvision5-armc6'
+    TOOLCHAIN = 'ARMC6'
+    TOOLCHAIN_NAME = '6070000::V6.7::.\ARMCLANG'
+
+    @classmethod
+    def is_target_supported(cls, target_name):
+        target = TARGET_MAP[target_name]
+        if not (set(target.supported_toolchains).intersection(
+                set(["ARMC6"]))):
+            return False
+        if not DeviceCMSIS.check_supported(target_name):
+            return False
+        if "Cortex-A" in target.core:
+            return False
+        if not hasattr(target, "post_binary_hook"):
+            return True
+        if target.post_binary_hook['function'] in cls.POST_BINARY_WHITELIST:
+            return True
+        else:
+            return False