Пример #1
0
def insertDeviceModules(moduleList, annotateParentsOnly=False):
     
    elabAreaConstraints = AreaConstraints(moduleList)
    # this was constructed upon the original call to load area.
    elabAreaConstraints.loadAreaConstraintsElaborated()

    for userAreaGroup in elabAreaConstraints.constraints.values():
  
        if('SYNTH_BOUNDARY' in userAreaGroup.attributes):  
             # Modify parent to know about this child.               
             parentModule = moduleList.modules[userAreaGroup.parentName]
             # pick up deps from parent. 
             moduleDeps ={} 
             moduleName = userAreaGroup.attributes['MODULE_NAME']

             # grab the parent module verilog and convert it. This
             # is really ugly, and demonstrates whe first class
             # language constructs are so nice.  Eventually, we
             # should push these new synth boundary objects into
             # flow earlier.
             moduleVerilog = None
             for dep in map(functools.partial(bsv_tool.modify_path_ba, moduleList), model.convertDependencies(moduleList.getAllDependenciesWithPaths('GEN_VERILOGS'))):
                 if (re.search(moduleName, dep)):
                     moduleVerilog = dep  
                  

             if(moduleVerilog is None):
                 print "ERROR: failed to find verilog for area group: " + userAreaGroup.name 
                 exit(1)
        
             moduleVerilogBlackBox = moduleVerilog.replace('.v', '_stub.v')

             moduleDeps['GEN_VERILOG_STUB'] = [moduleVerilogBlackBox]

             # We need to ensure that the second pass glue logic
             # modules don't look at the black box stubs.  The modules
             # are in the current synth boundaries list, but not in the LI graph.
             parentList = [parentModule, moduleList.topModule] + [module for module in moduleList.synthBoundaries() if not module.name in elabAreaConstraints.constraints]
             
             for parent in parentList:
                 print "BLACK_BOX Annotating: " + parent.name
                 if(parent.getAttribute('BLACK_BOX') is None):
                     parent.putAttribute('BLACK_BOX', {moduleVerilog: moduleVerilogBlackBox})
                 else:
                     blackBoxDict = parent.getAttribute('BLACK_BOX') 
                     blackBoxDict[moduleVerilog] = moduleVerilogBlackBox

             if(not annotateParentsOnly):            
                 moduleList.env.Command([moduleVerilogBlackBox], [moduleVerilog],
                                       'leap-gen-black-box -nohash $SOURCE > $TARGET')


                 m = Module(userAreaGroup.name, [moduleName],\
                             parentModule.buildPath, parentModule.name,\
                             [], parentModule.name, [], moduleDeps)
                 m.putAttribute("WRAPPER_NAME", moduleName)
                 m.putAttribute("AREA_GROUP", 1)
                 
                 moduleList.insertModule(m)
Пример #2
0
    def setupTreeBuild(self, moduleList, topo):
        useBVI = self.parent.USE_BVI
        env = moduleList.env

        root_directory = model.rootDir

        ##
        ## Load intra-Bluespec dependence already computed.  This
        ## information will ultimately drive the building of Bluespec
        ## modules. Build tree has a few dependencies which must be
        ## captured.
        ##

        ## If we aren't building the build tree, don't bother with its dependencies
        env.ParseDepends(get_build_path(moduleList, moduleList.topModule) + '/.depends-build-tree',
                         must_exist = not moduleList.env.GetOption('clean'))
        tree_base_path = env.Dir(get_build_path(moduleList, moduleList.topModule))

        tree_file_synth = tree_base_path.File('build_tree_synth.bsv')
        tree_file_synth_bo_path = tree_base_path.File(self.parent.TMP_BSC_DIR + '/build_tree_synth.bo')

        tree_file_wrapper = tree_base_path.File('build_tree_Wrapper.bsv')
        tree_file_wrapper_bo_path = tree_base_path.File(self.parent.TMP_BSC_DIR + '/build_tree_Wrapper.bo')

        # Area constraints
        area_constraints = None
        try:
            if (moduleList.getAWBParam('area_group_tool', 'AREA_GROUPS_ENABLE')):
                area_constraints = area_group_tool.AreaConstraints(moduleList)
        except:
            # The area constraints code is not present.
            pass

        boundary_logs = []
        for module in topo:
            # Remove any platform modules.. These are special in that
            # they can have wired interfaces.
            if (not module.platformModule):
                for log in module.moduleDependency['BSV_LOG']:
                    boundary_logs += [root_directory.File(log)]
        ##
        ## Back to SCons configuration (first) pass...
        ##

        top_module_path = get_build_path(moduleList, moduleList.topModule)

        # Inform object code build of the LI Graph retrieved from the
        # first pass.  Probe firstPassGraph for relevant object codes
        # (BA/NGC/BSV_SYNTH/BSV_SYNTH_BSH) accessed:
        # module.objectCache['NGC'] (these already have absolute
        # paths) I feel like the GEN_BAS/GEN_VERILOGS of the first
        # pass may be missing.  We insert these modules as objects in
        # the ModuleList.

        def makeAWBLink(doLink, source, buildPath, uniquifier=''):
            base_file = os.path.basename(str(source))
            link_dir = buildPath + '/.li'
            link_path =  link_dir + '/' + uniquifier + base_file
            if (doLink):
                if (os.path.lexists(link_path)):
                    os.remove(link_path)
                rel = os.path.relpath(str(source), link_dir)
                print 'Linking: ' + link_path + ' -> ' + rel
                os.symlink(rel, link_path)

            return link_path


        limLinkUserSources = []
        limLinkUserTargets = []
        limLinkPlatformSources = []
        limLinkPlatformTargets = []
        importStubs = []


        if (not self.getFirstPassLIGraph is None):
            # Now that we have demanded bluespec builds (for
            # dependencies), we should now should downgrade synthesis boundaries for the backend.
            oldStubs = []
            for module in topo:
                if(not module.platformModule):
                    if((not module.name in self.getFirstPassLIGraph.modules) or (self.getFirstPassLIGraph.modules[module.name].getAttribute('RESYNTHESIZE') is None)): 
                        module.liIgnore = True
                    # this may not be needed.
                    else:
                        oldStubs += module.moduleDependency['GEN_VERILOG_STUB']

            # let's pick up the platform dependencies, since they are also special.
            env.ParseDepends(get_build_path(moduleList, moduleList.topModule) + '/.depends-platform',
                             must_exist = not moduleList.env.GetOption('clean'))

            # Due to the way that string files are
            # generated, they are difficult to rename in
            # the front-end compilation. This leads to
            # collisions amoung similarly-typed LI
            # Modules.  We fix it by uniquifying the links.

            def getModuleName(module):
                return module.name

            def getEmpty(module):
                return ''

            linkthroughMap = {'BA': getEmpty, 'GEN_BAS': getEmpty, 'GEN_VERILOGS': getEmpty, 'GEN_VERILOG_STUB': getEmpty, 'STR': getModuleName}

            buildPath = get_build_path(moduleList, moduleList.topModule)
            for module in self.getFirstPassLIGraph.modules.values():
            
                # do not link through those modules marked for resynthesis. 
                if(not module.getAttribute('RESYNTHESIZE') is None):  
                    continue

                moduleDeps = {}

                for objType in linkthroughMap:
                    if(objType in module.objectCache):
                        localNames =  map(lambda fileName: makeAWBLink(False,
                                                                       fileName.from_bld(),
                                                                       buildPath, 
                                                                       uniquifier=linkthroughMap[objType](module)),
                                          module.objectCache[objType])

                        # The previous passes GEN_VERILOGS are not
                        # really generated here, so we can't call them
                        # as such. Tuck them in to 'VERILOG'
                        if(objType == 'GEN_VERILOG_STUB'):
                            oldStubs += localNames                        
                        moduleDeps[objType] = localNames

                        if (module.getAttribute('PLATFORM_MODULE') is None):
                            limLinkUserTargets += localNames
                            limLinkUserSources += module.objectCache[objType]
                        else:
                            limLinkPlatformTargets += localNames
                            limLinkPlatformSources += module.objectCache[objType]

                m = Module(module.name, ["mk_" + module.name + "_Wrapper"],\
                           moduleList.topModule.buildPath, moduleList.topModule.name,\
                           [], moduleList.topModule.name, [], moduleDeps)

                moduleList.insertModule(m)
        else:
            # The top module/build pipeline only depend on non-platformModules
            oldStubs = [module.moduleDependency['GEN_VERILOG_STUB'] for module in moduleList.synthBoundaries() if not module.platformModule]




        ## Enumerate the dependencies created by the build tree.
        buildTreeDeps = {}

        ## We have now generated a completely new module. Let's throw it
        ## into the list.  Although we are building it seperately, this
        ## module is an extension to the build tree.
        expected_wrapper_count = len(boundary_logs) - 2
        importBOs = []

        if (not self.getFirstPassLIGraph is None):
            # we now have platform modules in here.
            expected_wrapper_count = len(self.getFirstPassLIGraph.modules) - 2

            # If we have an LI graph, we need to construct and compile
            # LI import wrappers for the modules we received from the
            # first pass.  Do that here.  include all the dependencies
            # in the graph in the wrapper.
            liGraph = LIGraph([])
            firstPassGraph = self.getFirstPassLIGraph
            # We should ignore the 'PLATFORM_MODULE'
            liGraph.mergeModules([ module for module in bsv_tool.getUserModules(firstPassGraph) if module.getAttribute('RESYNTHESIZE') is None])
            for module in sorted(liGraph.graph.nodes(), key=lambda module: module.name):
                # pull in the dependecies generate by the dependency pass.
                env.ParseDepends(str(tree_base_path) + '/.depends-' + module.name,
                                 must_exist = not moduleList.env.GetOption('clean'))
                wrapper_path = tree_base_path.File(module.name + '_Wrapper.bsv')
                wrapper_bo_path = tree_base_path.File(self.parent.TMP_BSC_DIR + '/' + module.name + '_Wrapper.bo')

                # include commands to build the wrapper .bo/.ba
                # Here, we won't be using the generated .v (it's garbage), so we intentionally  get rid of it.
                importVDir = env.Dir('.lim_import_verilog')
                if not os.path.isdir(str(importVDir)):
                   os.mkdir(str(importVDir))

                wrapper_command = self.parent.compile_bo_bsc_base([wrapper_bo_path], get_build_path(moduleList, moduleList.topModule), vdir=importVDir) + ' $SOURCES'
                wrapper_bo = env.Command([wrapper_bo_path],
                                         [wrapper_path],
                                         wrapper_command)
                # create BO.
                importBOs += [wrapper_bo]

        verilog_deps = [ "__TREE_MODULE__" + str(id) for id in range(expected_wrapper_count)]

        if(self.parent.BUILD_LOGS_ONLY == 0):
            buildTreeDeps['GEN_VERILOGS'] = ["mk_" + vlog + '_Wrapper' + ".v"  for vlog in verilog_deps]
        else:
            buildTreeDeps['GEN_VERILOGS'] = []

        buildTreeDeps['GEN_BAS'] = [  "mk_" + vlog + '_Wrapper' + ".ba" for vlog in verilog_deps]
        buildTreeDeps['BA'] = []
        buildTreeDeps['STR'] = []
        buildTreeDeps['VERILOG'] = [top_module_path + '/' + self.parent.TMP_BSC_DIR + '/mk_build_tree_Wrapper.v']
        buildTreeDeps['GIVEN_BSVS'] = []
        buildTreeDeps['VERILOG_STUB'] = model.convertDependencies(oldStubs)

        tree_module = Module( 'build_tree', ["mkBuildTree"], moduleList.topModule.buildPath,\
                             moduleList.topModule.name,\
                             [], moduleList.topModule.name, [], buildTreeDeps, platformModule=True)

        tree_module.putAttribute('LI_GRAPH_IGNORE', True)

        moduleList.insertModule(tree_module)    
        wrapper_gen_tool.generateAWBCompileWrapper(moduleList, tree_module)

        ## This produces the treeNode BSV. It must wait for the
        ## compilation of the log files, which it will read to form the
        ## LIM graph
        ##
        ## We do two operations during this phase.  First, we dump a
        ## representation of the user program. This representation is
        ## used by the LIM compiler to create heterogeneous
        ## executables.  We then do a local modification to the build
        ## tree to reduce Bluespec compilation time.

        # If I got an LI graph, I don't care about the boundary logs.
        # In this case, everything comes from the first pass graph.

        # Usually, we only need logs and BOs to build the build tree.
        # However, during the second pass build we also need to fill
        # in information about area group paths (changed by tree build)
        tree_build_deps = boundary_logs + importBOs
        tree_build_results = [tree_file_wrapper, tree_file_synth]

        if (self.getFirstPassLIGraph and area_constraints):
            tree_build_deps += [area_constraints.areaConstraintsFilePlaced()]
            tree_build_results += [area_constraints.areaConstraintsFile()]

        ##
        ## The cutTreeBuild builder function needs some of the local state
        ## in the current function.  Build a dictionary with the required
        ## state and partial instance of cutTreeBuild with the state applied.
        ##
        cut_tree_state = dict()
        cut_tree_state['area_constraints'] = area_constraints
        cut_tree_state['boundary_logs'] = boundary_logs
        cut_tree_state['moduleList'] = moduleList
        cut_tree_state['tree_file_synth'] = tree_file_synth
        cut_tree_state['tree_file_wrapper'] = tree_file_wrapper

        cut_tree_build = functools.partial(self.cutTreeBuild, cut_tree_state)
        cut_tree_build.__name__ = 'cutTreeBuild'

        tree_components = env.Command(tree_build_results,
                                      tree_build_deps,
                                      cut_tree_build)

        ## Compiling the build tree wrapper produces several .ba
        ## files, some that are useful, the TREE_MODULES, and some
        ## which are not, the _Wrapper.ba.  As a result, we dump the
        ## tree build output to a different directory, so as not to
        ## pollute the existing build.  Here, we link to the relevant
        ## files in that directory.

        def linkLIMObjClosure(liModules, buildPath):
            def linkLIMObj(target, source, env):
                if (not self.getFirstPassLIGraph is None):
                    # The LIM build has passed us some source and we need
                    # to patch it through.
                    for module in liModules:
                        for objType in linkthroughMap:
                            if(objType in module.objectCache):                
                                map(lambda fileName: makeAWBLink(True, fileName.from_bld(), buildPath, uniquifier=linkthroughMap[objType](module)),
                                    module.objectCache[objType])

            return linkLIMObj


        ## The top level build depends on the compilation of the tree components
        ## into bo/ba/v files.

        # the GEN_BAS attached to the build tree need to be massaged
        # to reflect their actual path.  Perhaps we should be using
        # some kind of object that makes these sorts of conversions
        # simpler.

        producedBAs = map(lambda path: bsv_tool.modify_path_ba(moduleList, path), moduleList.getModuleDependenciesWithPaths(tree_module, 'GEN_BAS'))
        producedVs = map(lambda path: bsv_tool.modify_path_ba(moduleList, path), moduleList.getModuleDependenciesWithPaths(tree_module, 'GEN_VERILOGS')) + \
                     buildTreeDeps['VERILOG']

        tree_command = self.parent.compile_bo_bsc_base([tree_file_wrapper_bo_path], get_build_path(moduleList, moduleList.topModule)) + ' ' + tree_file_wrapper.path
        tree_file_wrapper_bo = env.Command([tree_file_wrapper_bo_path] + producedBAs + producedVs,
                                           tree_components,
                                           tree_command)

        # If we got a first pass LI graph, we need to link its object codes.
        if (not self.getFirstPassLIGraph is None):
            srcs = [s.from_bld() for s in limLinkUserSources]
            link_lim_user_objs = env.Command(limLinkUserTargets,
                                             srcs,
                                             linkLIMObjClosure([ module for module in bsv_tool.getUserModules(firstPassGraph) if module.getAttribute('RESYNTHESIZE') is None],
                                                               tree_base_path.path))
            env.Depends(link_lim_user_objs, tree_file_wrapper_bo)


        # the tree_file_wrapper build needs all the wrapper bo from the user program,
        # but not the top level build.
        top_bo = moduleList.topModule.moduleDependency['BSV_BO']
        all_bo = moduleList.getAllDependencies('BO')

        env.Depends(tree_file_wrapper_bo, all_bo)

        tree_synth_command = self.parent.compile_bo_bsc_base([tree_file_synth_bo_path], get_build_path(moduleList, moduleList.topModule)) + ' ' + tree_file_synth.path
        tree_file_synth_bo = env.Command([tree_file_synth_bo_path],
                                         [tree_file_synth, tree_file_wrapper_bo],
                                         tree_synth_command)

        env.Depends(top_bo, tree_file_synth_bo)
        env.Depends(moduleList.topModule.moduleDependency['BSV_LOG'],
                    tree_file_synth_bo)


        #Handle the platform_synth build, which is special cased.
        platform_synth = get_build_path(moduleList, moduleList.topModule) + "/" +  moduleList.localPlatformName + "_platform_synth.bsv"
        platform_synth_bo_path = get_build_path(moduleList, moduleList.topModule) + "/" + self.parent.TMP_BSC_DIR +"/" + moduleList.localPlatformName + "_platform_synth"
        # if we are in the lim linking phase, we need to change the
        # vdir directory to hide the spurious verilog generated by
        # bluespec.
        importVDir = None
        if(not self.getFirstPassLIGraph is None):
            importVDir = env.Dir('.lim_import_verilog')
            if not os.path.isdir(str(importVDir)):
                os.mkdir(str(importVDir))

        platform_synth_command = self.parent.compile_bo_bsc_base([platform_synth_bo_path + '.bo'], get_build_path(moduleList, moduleList.topModule), vdir=importVDir) + ' $SOURCE'
        platform_wrapper_bo = get_build_path(moduleList, moduleList.topModule) + "/" + self.parent.TMP_BSC_DIR + "/" +moduleList.localPlatformName + '_platform_Wrapper.bo'

        platform_synth_deps = [platform_synth]
        #if we have a module graph, we don't require the compilation of the platform_wrapper_bo.
        if (self.getFirstPassLIGraph is None):
            platform_synth_deps.append(platform_wrapper_bo)
        platform_synth_bo = env.Command([platform_synth_bo_path + '.bo'],
                                         platform_synth_deps,
                                         platform_synth_command)
        # this produces a ba also?
        env.Depends(moduleList.topModule.moduleDependency['BSV_LOG'],
                        platform_synth_bo)

        # Platform synth does the same object-bypass dance as tree_module.
        if(not self.getFirstPassLIGraph is None):
            srcs = [s.from_bld() for s in limLinkPlatformSources]
            link_lim_platform_objs = env.Command(limLinkPlatformTargets,
                                                 srcs,
                                                 linkLIMObjClosure([ module for module in bsv_tool.getPlatformModules(firstPassGraph) if module.getAttribute('RESYNTHESIZE') is None],
                                                                   tree_base_path.path))
            env.Depends(link_lim_platform_objs, platform_synth_bo)

        # need to generate a stub file for the build tree module.
        # note that in some cases, there will be only one module in
        # the graph, usually in a multifpga build.  In this case,
        # the build_tree module will be vestigal, but since we can't
        # predict this statically we'll have to build it anyway.

        tree_module.moduleDependency['GEN_VERILOG_STUB'] = [self.parent.stubGenCommand(top_module_path,
                                                                                       "build_tree",
                                                                                       top_module_path + '/' + self.parent.TMP_BSC_DIR + "/mk_build_tree_Wrapper.v")]

        # top level only depends on platform modules
        moduleList.topModule.moduleDependency['VERILOG_STUB'] = model.convertDependencies([module.moduleDependency['GEN_VERILOG_STUB'] for module in moduleList.synthBoundaries() if module.platformModule])
        if(not self.getFirstPassLIGraph is None):
            #Second pass build picks up stub files from the first pass build.
            moduleList.topModule.moduleDependency['VERILOG_STUB'] += model.convertDependencies(oldStubs)