def generateWrapperStub(moduleList, module): suffixes=['_Wrapper.bsv','_Log.bsv'] compileWrapperPath = get_build_path(moduleList, module) for suffix in suffixes: # check for file's existance before overwriting. wrapperPath = compileWrapperPath + '/' + module.name + suffix if(os.path.exists(wrapperPath)): # No need to dump a spurious wrapper. continue wrapper = open(wrapperPath, 'w') wrapper.write('// Wrapper Stub. This file was created by wrapper-gen\n') wrapper.write('import Vector::*;\n') generateWellKnownIncludes(wrapper) wrapper.write('// import non-synthesis public files\n') wrapper.write('`include "' + module.name + '_compile.bsv"\n') ## Import all other modules used in the build. On the first pass this ## is simply all modules. After that import only the modules used ## on the platform. first_pass_LI_graph = getFirstPassLIGraph() import_modules = [] if (first_pass_LI_graph is None): import_modules = [m for m in moduleList.synthBoundaries() if not m.platformModule] else: import_modules = bsv_tool.getUserModules(first_pass_LI_graph) for m in sorted(import_modules, key=lambda m: m.name): wrapper.write('import ' + m.name + '_Wrapper::*;\n') wrapper.close()
def compile_bo_closure(source, target, env, for_signature): cmd = '' if (str(source[0]) != get_build_path(self.moduleList, self.moduleList.topModule) + '/' + self.moduleList.topModule.name + '.bsv'): cmd = self.compile_bo_bsc_base( target, module_path) + ' -D CONNECTION_SIZES_KNOWN ' + str( source[0]) return cmd
def generateAWBCompileWrapper(moduleList, module): compileWrapperPath = get_build_path(moduleList, module) wrapper = open( compileWrapperPath + '/' + module.name + '_compile.bsv', 'w') wrapper.write('// AWB Compile Wrapper. This file was created by wrapper-gen\n') wrapper.write('`define BUILDING_MODULE_' + module.name + '\n') for includeClass in ['GIVEN_BSVS', 'WRAPPER_BSHS']: if (includeClass in module.moduleDependency): for file in module.moduleDependency[includeClass]: wrapper.write('`include "' + file +'"\n') wrapper.close()
def getModuleRTLs(moduleList, module): moduleVerilogs = [] moduleVHDs = [] MODULE_PATH = model.get_build_path(moduleList, module) for v in moduleList.getDependencies(module, 'GEN_VERILOGS'): moduleVerilogs += [MODULE_PATH + '/' + moduleList.env['DEFS']['TMP_BSC_DIR'] + '/' + v] for v in moduleList.getDependencies(module, 'GIVEN_VERILOGS'): moduleVerilogs += [MODULE_PATH + '/' + v] for v in moduleList.getDependencies(module, 'GIVEN_VHDS'): moduleVHDs += [MODULE_PATH + '/' + v] for v in moduleList.getDependencies(module, 'GIVEN_VHDLS'): lib = "" if('lib' in v.attributes): lib = v.attributes['lib'] + '/' moduleVHDs += [model.Source.Source(MODULE_PATH + '/' + lib + v.file, v.attributes)] return [moduleVerilogs, moduleVHDs]
def getSynthHandle(moduleList, module): compileWrapperPath = get_build_path(moduleList, module) path = compileWrapperPath + '/' + module.name + '_synth.bsv' print "Generating synthesis stub: " + path return open(path, 'w')
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)
def compile_bo_closure(source, target, env, for_signature): cmd = '' if (str(source[0]) != get_build_path(self.moduleList, self.moduleList.topModule) + '/' + self.moduleList.topModule.name + '.bsv'): cmd = self.compile_bo_bsc_base(target, module_path) + ' -D CONNECTION_SIZES_KNOWN ' + str(source[0]) return cmd
def build_synth_boundary(self, moduleList, module): if (self.pipeline_debug != 0): print "Working on " + module.name env = moduleList.env BSVS = moduleList.getSynthBoundaryDependencies(module, 'GIVEN_BSVS') # each submodel will have a generated BSV GEN_BSVS = moduleList.getSynthBoundaryDependencies(module, 'GEN_BSVS') APM_FILE = moduleList.env['DEFS']['APM_FILE'] BSC = moduleList.env['DEFS']['BSC'] MODULE_PATH = get_build_path(moduleList, module) ## ## Load intra-Bluespec dependence already computed. This information will ## ultimately drive the building of Bluespec modules. ## env.ParseDepends(MODULE_PATH + '/' + module.dependsFile, must_exist=not moduleList.env.GetOption('clean')) # This function is responsible for creating build rules for # subdirectories. It must be called or no subdirectory builds # will happen since scons won't have the recipe. self.setup_module_build(moduleList, MODULE_PATH) if not os.path.isdir(self.TMP_BSC_DIR): os.mkdir(self.TMP_BSC_DIR) moduleList.env.VariantDir(MODULE_PATH + '/' + self.TMP_BSC_DIR, '.', duplicate=0) # set up builds for the various bsv of this synthesis # boundary. One wonders if we could handle this as a single # global operation. bsc_builds = [] for bsv in BSVS + GEN_BSVS: bsc_builds += env.BSC( MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', ''), MODULE_PATH + '/' + bsv) firstPassLIGraph = wrapper_gen_tool.getFirstPassLIGraph() # In the second pass of the LIM build, we don't need to build # any modules, except in some cases where we turn on # module-specific optimizations, as in the case of central # cache. If we do need to rebuild, we'll see a tag. if ((module.name != moduleList.topModule.name) and (not firstPassLIGraph is None) and (module.name in firstPassLIGraph.modules) and (firstPassLIGraph.modules[module.name].getAttribute('RESYNTHESIZE') is None)): return # This should not be a for loop. for bsv in [model.get_wrapper(module)]: if env.GetOption('clean'): os.system('rm -f ' + MODULE_PATH + '/' + bsv.replace('Wrapper.bsv', 'Log.bsv')) os.system('rm -f ' + MODULE_PATH + '/' + bsv.replace('.bsv', '_con_size.bsh')) ## ## First pass just generates a log file to figure out cross synthesis ## boundary soft connection array sizes. ## ## All but the top level build need the log build pass to compute ## the size of the external soft connection vector. The top level has ## no exposed connections and can generate the log file, needed ## for global strings, during the final build. ## logfile = model.get_logfile(moduleList, module) module.moduleDependency['BSV_LOG'] += [logfile] module.moduleDependency['GEN_LOGS'] = [logfile] if (module.name != moduleList.topModule.name): log = env.BSC_LOG_ONLY( logfile, MODULE_PATH + '/' + bsv.replace('Wrapper.bsv', 'Log')) ## ## Parse the log, generate a stub file ## stub_name = bsv.replace('.bsv', '_con_size.bsh') def build_con_size_bsh_closure(target, source, env): liGraph = LIGraph(li_module.parseLogfiles(source)) # Should have only one module... if (len(liGraph.modules) == 0): bshModule = LIModule(module.name, module.name) else: bshModule = liGraph.modules.values()[0] bsh_handle = open(str(target[0]), 'w') wrapper_gen_tool.generateConnectionBSH( bshModule, bsh_handle) bsh_handle.close() stub = env.Command(MODULE_PATH + '/' + stub_name, log, build_con_size_bsh_closure) ## ## Now we are ready for the real build ## if (module.name != moduleList.topModule.name): wrapper_bo = env.BSC( MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', ''), MODULE_PATH + '/' + bsv) moduleList.env.Depends(wrapper_bo, stub) module.moduleDependency['BO'] = [wrapper_bo] if (self.BUILD_LOGS_ONLY): model_dir = self.hw_dir.Dir( moduleList.env['DEFS']['ROOT_DIR_MODEL']) module.moduleDependency['BSV_SCHED'] = \ [moduleList.env.Command(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.ba.sched', wrapper_bo, 'bluetcl ' + model_dir.File('sched.tcl').path + ' -p ' + self.ALL_BUILD_DIR_PATHS + ' --m ' + module.wrapperName() + ' > $TARGET')] module.moduleDependency['BSV_PATH'] = \ [moduleList.env.Command(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.ba.path', wrapper_bo, 'bluetcl ' + model_dir.File('path.tcl').path + ' -p ' + self.ALL_BUILD_DIR_PATHS + ' --m ' + module.wrapperName() + ' > $TARGET')] moduleList.topDependency += \ module.moduleDependency['BSV_SCHED'] + module.moduleDependency['BSV_PATH'] module.moduleDependency['BSV_IFC'] = \ [moduleList.env.Command(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.ba.ifc', wrapper_bo, 'bluetcl ' + model_dir.File('interfaceType.tcl').path + ' -p ' + self.ALL_BUILD_DIR_PATHS + ' --m ' + module.wrapperName() + ' | python site_scons/model/PythonTidy.py > $TARGET')] moduleList.topDependency += module.moduleDependency[ 'BSV_IFC'] else: ## Top level build can generate the log in a single pass since no ## connections are exposed wrapper_bo = env.BSC_LOG( MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', ''), MODULE_PATH + '/' + bsv) ## SCons doesn't deal well with logfile as a 2nd target to BSC_LOG rule, ## failing to derive dependence correctly. module.moduleDependency['BSV_BO'] = [wrapper_bo] log = env.Command(logfile, wrapper_bo, '') env.Precious(logfile) ## In case Bluespec build is the end of the build pipeline. if (not self.BUILD_LOGS_ONLY): moduleList.topDependency += [log] ## The toplevel bo also depends on the on the synthesis of the build tree from log files. ## ## Meta-data written during compilation to separate files. ## glob_str = env.Command( MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', '.str'), wrapper_bo, '') env.Precious(glob_str) module.moduleDependency['STR'] = [glob_str] ## All but the top level build need the log build pass to compute ## the size of the external soft connection vector. The top level has ## no exposed connections and needs no log build pass. ## if (module.name != moduleList.topModule.name): if (self.pipeline_debug != 0): print 'wrapper_bo: ' + str(wrapper_bo) print 'stub: ' + str(stub) synth_stub_path = moduleList.env['DEFS'][ 'ROOT_DIR_HW'] + '/' + module.buildPath + '/' synth_stub = synth_stub_path + module.name + '_synth.bsv' # This stub may be needed in certain compilation flows. Note its presence here. module.moduleDependency['BSV_SYNTH'] = [ module.name + '_synth.bsv' ] module.moduleDependency['BSV_SYNTH_BSH'] = [ module.name + '_Wrapper_con_size.bsh' ] def build_synth_stub(target, source, env): liGraph = LIGraph(li_module.parseLogfiles(source)) # Should have only one module... if (len(liGraph.modules) == 0): synthModule = LIModule(module.name, module.name) else: synthModule = liGraph.modules.values()[0] synth_handle = open(target[0].path, 'w') wrapper_gen_tool.generateSynthWrapper( synthModule, synth_handle, moduleList.localPlatformName, moduleType=module.interfaceType, extraImports=module.extraImports, synthBoundaryModule=module) synth_handle.close() env.Command( synth_stub, # target logfile, build_synth_stub) ## ## The mk_<wrapper>.v file is really built by the Wrapper() builder ## above. We use NULL commands to convince SCons the file is generated. ## This seems easier than SCons SideEffect() calls, which don't clean ## targets. ## ## We also generate all this synth boundary's GEN_VS ## ext_gen_v = [] for v in moduleList.getSynthBoundaryDependencies(module, 'GEN_VS'): ext_gen_v += [MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + v] # Add the dependence for all Verilog noted above bld_v = env.Command([ MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.v' ] + ext_gen_v, MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', '.bo'), '') env.Precious(bld_v) if (moduleList.getAWBParam('bsv_tool', 'BUILD_VERILOG') == 1): module.moduleDependency['VERILOG'] += [bld_v] + [ext_gen_v] module.moduleDependency['GEN_WRAPPER_VERILOGS'] = [ os.path.basename(module.wrapperName() + '.v') ] if (self.pipeline_debug != 0): print "Name: " + module.name # each synth boundary will produce a ba bld_ba = [ env.Command([ MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.ba' ], MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', '.bo'), '') ] module.moduleDependency['BA'] += bld_ba env.Precious(bld_ba) ## ## Build the Verilog black-box stub. ## bb = self.stubGenCommand(MODULE_PATH, module.boundaryName, bld_v) # Only the subordinate modules have stubs. # The platform module should not be enumerated here. This is a false dependency. if (module.name != moduleList.topModule.name): moduleList.topModule.moduleDependency['VERILOG_STUB'] += [bb] module.moduleDependency['GEN_VERILOG_STUB'] = [bb] return [bb] #This doesn't seem to do anything.
def __init__(self, moduleList, isPrimaryBuildTarget): APM_NAME = moduleList.env['DEFS']['APM_NAME'] BSC = moduleList.env['DEFS']['BSC'] inc_paths = moduleList.swIncDir # we need to depend on libasim self.firstPassLIGraph = wrapper_gen_tool.getFirstPassLIGraph() # This is not correct for LIM builds and needs to be fixed. TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ALL_DIRS_FROM_ROOT = moduleList.env['DEFS']['ALL_HW_DIRS'] ALL_BUILD_DIRS_FROM_ROOT = model.transform_string_list(ALL_DIRS_FROM_ROOT, ':', '', '/' + TMP_BSC_DIR) ALL_INC_DIRS_FROM_ROOT = '-Xv +incdir+' + ALL_DIRS_FROM_ROOT.replace(':','+') ALL_LIB_DIRS_FROM_ROOT = ALL_DIRS_FROM_ROOT + ':' + ALL_BUILD_DIRS_FROM_ROOT # Due to the bluespec linker, for LI second pass builds, the final # verilog link step must occur in a different directory than the # bsc object code wrapper compilation step. However, non-LIM # linker builds need to build in the original .bsc directory to # pick up VPI. vexe_vdir = moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + moduleList.env['DEFS']['ROOT_DIR_MODEL'] + '/' + moduleList.env['DEFS']['TMP_BSC_DIR'] if(not self.firstPassLIGraph is None): vexe_vdir = vexe_vdir + '_vlog' if not os.path.isdir(vexe_vdir): os.mkdir(vexe_vdir) LI_LINK_DIR = "" if (not self.firstPassLIGraph is None): LI_LINK_DIR = model.get_build_path(moduleList, moduleList.topModule) + "/.li/" inc_paths += [LI_LINK_DIR] ALL_LIB_DIRS_FROM_ROOT = LI_LINK_DIR + ':' + ALL_LIB_DIRS_FROM_ROOT liCodeType = ['VERILOG', 'GIVEN_VERILOG_HS', 'GEN_VPI_CS', 'GEN_VPI_HS'] # This can be refactored as a function. if (not self.firstPassLIGraph is None): for moduleName in self.firstPassLIGraph.modules: moduleObject = self.firstPassLIGraph.modules[moduleName] for codeType in liCodeType: if(codeType in moduleObject.objectCache): for verilog in moduleObject.objectCache[codeType]: linkPath = vexe_vdir + '/' + os.path.basename(verilog) def linkVerilog(target, source, env): # It might be more useful if the Module contained a pointer to the LIModules... if(os.path.lexists(str(target[0]))): os.remove(str(target[0])) print "Linking: " + str(source[0]) + " to " + str(target[0]) os.symlink(str(source[0]), str(target[0])) moduleList.env.Command(linkPath, verilog, linkVerilog) if(codeType in moduleList.topModule.moduleDependency): moduleList.topModule.moduleDependency[codeType] += [linkPath] else: moduleList.topModule.moduleDependency[codeType] = [linkPath] else: # Warn that we did not find the ngc we expected to find.. print "Warning: We did not find verilog for module " + moduleName bsc_version = bsv_tool.getBluespecVersion() ldflags = '' for ld_file in moduleList.getAllDependenciesWithPaths('GIVEN_BLUESIM_LDFLAGSS'): ldHandle = open(moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + ld_file, 'r') ldflags += ldHandle.read() + ' ' BSC_FLAGS_VERILOG = '-steps 10000000 +RTS -K1000M -RTS -keep-fires -aggressive-conditions -wait-for-license -no-show-method-conf -no-opt-bool -licenseWarning 7 -elab -show-schedule ' + ldflags + ' -verilog -v -vsim vcs ' # Build in parallel. n_jobs = moduleList.env.GetOption('num_jobs') if (bsc_version >= 30006): BSC_FLAGS_VERILOG += '-parallel-sim-link ' + str(n_jobs) + ' ' for path in inc_paths: BSC_FLAGS_VERILOG += ' -I ' + path + ' ' LDFLAGS = moduleList.env['DEFS']['LDFLAGS'] TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ROOT_WRAPPER_SYNTH_ID = 'mk_' + moduleList.env['DEFS']['ROOT_DIR_MODEL'] + '_Wrapper' vexe_gen_command = \ BSC + ' ' + BSC_FLAGS_VERILOG + ' -vdir ' + vexe_vdir + ' -simdir ' + vexe_vdir + ' -bdir ' + vexe_vdir +' -p +:' + ALL_LIB_DIRS_FROM_ROOT + ' -vsearch +:' + ALL_LIB_DIRS_FROM_ROOT + ' ' + \ ' -o $TARGET' if (bsc_version >= 13013): # 2008.01.A compiler allows us to pass C++ arguments. if (model.getDebug(moduleList)): vexe_gen_command += ' -Xc++ -O0' else: vexe_gen_command += ' -Xc++ -O1' # g++ 4.5.2 is complaining about overflowing the var tracking table if (model.getGccVersion() >= 40501): vexe_gen_command += ' -Xc++ -fno-var-tracking-assignments' defs = (software_tool.host_defs()).split(" ") for definition in defs: vexe_gen_command += ' -Xc++ ' + definition + ' -Xc ' + definition # cflags to be passed into vcs compiler for definition in defs: vexe_gen_command += ' -Xv -CFLAGS -Xv ' + definition for path in inc_paths: vexe_gen_command += ' -Xv -CFLAGS -Xv -I' + path for lib in moduleList.swLinkLibs: vexe_gen_command += ' -Xl -l' + lib + ' ' vexe_gen_command += ' -Xv -LDFLAGS -Xv -l' + lib + ' ' # construct full path to BAs def modify_path(str): array = str.split('/') file = array.pop() return moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + '/'.join(array) + '/' + TMP_BSC_DIR + '/' + file vexe_gen_command += ' -Xv -full64 ' vexe_gen_command += ' -Xv -sverilog ' vexe_gen_command += ' -Xv +librescan ' vexe_gen_command += ' -Xv +libext+.sv ' if(moduleList.getAWBParam('verilog_tool', 'VCS_ARGUMENTS')): vexe_gen_command += moduleList.getAWBParam('verilog_tool', 'VCS_ARGUMENTS') vexe_gen_command += ' ' + ALL_INC_DIRS_FROM_ROOT + ' ' # VCS must be informed of all BDPI. Really we need some kind of # file object here. All this massaging of path is ridiculous. vexe_gen_command += ' -Xv ' + moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + (' -Xv ' + moduleList.env['DEFS']['ROOT_DIR_HW'] + '/').join(moduleList.getAllDependenciesWithPaths('GIVEN_BDPI_CS')) + ' ' # Bluespec requires that source files terminate the command line. vexe_gen_command += '-verilog -e ' + ROOT_WRAPPER_SYNTH_ID + ' ' +\ moduleList.env['DEFS']['BDPI_CS'] if (model.getBuildPipelineDebug(moduleList) != 0): for m in moduleList.getAllDependencies('BA'): print 'BA dep: ' + str(m) for m in moduleList.getAllDependencies('VERILOG'): print 'VL dep: ' + str(m) for m in moduleList.getAllDependencies('VHDL'): print 'BA dep: ' + str(m) for m in moduleList.getAllDependencies('GIVEN_BDPI_CS'): print 'GIVEN_BDPI_CS: ' + str(m) # Generate a thin wrapper around the verilog executable. This # wrapper is used to address a problem in iverilog in which the # simulator does not support shared library search paths. The # current wrapper only works for iverilog. Due to brokeness in # the iverilog argument parser, we must construct a correct # iverilog command line by analyzing its compiled script. Also, # this script is not passing through the arguments that it should # be passing through. def generate_vexe_wrapper(target, source, env): wrapper_handle = open(str(target[0]),'w') wrapper_handle.write('#!/usr/bin/perl\n') wrapper_handle.write('# generated by verilog.py\n') wrapper_handle.write('$platform = $ENV{"PLATFORM_DIRECTORY"};\n') wrapper_handle.write('$ENV{LD_LIBRARY_PATH} = $platform . ":" . $ENV{LD_LIBRARY_PATH};\n') wrapper_handle.write('`ln -sf $platform/directc_mk_model_Wrapper.so .`;\n') wrapper_handle.write('exec("$platform/' + TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe -licqueue \$* ");\n') wrapper_handle.close() def modify_path_ba_local(path): return bsv_tool.modify_path_ba(moduleList, path) # Bluesim builds apparently touch this code. This control block # preserves their behavior, but it is unclear why the verilog build is # involved. if (isPrimaryBuildTarget): vbinDeps = [] # If we got a lim graph, we'll pick up many of our dependencies from it. # These were annotated in the top module above. Really, this seems unclean. # we should build a graph during the second pass and just use it. if(not self.firstPassLIGraph is None): vbinDeps += moduleList.getDependencies(moduleList.topModule, 'VERILOG') + moduleList.getDependencies(moduleList.topModule, 'GIVEN_VERILOG_HS') + moduleList.getDependencies(moduleList.topModule, 'GEN_VPI_HS') + moduleList.getDependencies(moduleList.topModule, 'GEN_VPI_CS') +moduleList.getDependencies(moduleList.topModule, 'VHDL') + moduleList.getDependencies(moduleList.topModule, 'BA') + map(modify_path_ba_local, moduleList.getModuleDependenciesWithPaths(moduleList.topModule, 'GEN_BAS')) # collect dependencies from all awb modules else: vbinDeps += moduleList.getAllDependencies('VERILOG') + moduleList.getAllDependencies('VHDL') + moduleList.getAllDependencies('BA') + map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')) vbin = moduleList.env.Command( TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe', vbinDeps, [ vexe_gen_command ]) moduleList.env.AlwaysBuild(vbin) vexe = moduleList.env.Command( APM_NAME + '_hw.exe', vbin, [ generate_vexe_wrapper, '@chmod a+x $TARGET', SCons.Script.Delete(APM_NAME + '_hw.errinfo') ]) moduleList.topDependency = moduleList.topDependency + [vexe] else: vbin = moduleList.env.Command( TMP_BSC_DIR + '/' + APM_NAME + '_hw.vexe', moduleList.getAllDependencies('VERILOG') + moduleList.getAllDependencies('VHDL') + moduleList.getAllDependencies('BA') + map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')), [ vexe_gen_command ]) vexe = moduleList.env.Command( APM_NAME + '_hw.vexe', vbin, [ generate_vexe_wrapper, '@chmod a+x $TARGET', SCons.Script.Delete(APM_NAME + '_hw.exe'), SCons.Script.Delete(APM_NAME + '_hw.errinfo') ]) moduleList.env.Alias('vexe', vexe)
def __init__(self, moduleList, isPrimaryBuildTarget): # if we have a deps build, don't do anything... if (moduleList.isDependsBuild): return APM_NAME = moduleList.env['DEFS']['APM_NAME'] BSC = moduleList.env['DEFS']['BSC'] inc_paths = moduleList.swIncDir # we need to depend on libasim self.firstPassLIGraph = wrapper_gen_tool.getFirstPassLIGraph() # This is not correct for LIM builds and needs to be fixed. TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ALL_DIRS_FROM_ROOT = moduleList.env['DEFS']['ALL_HW_DIRS'] ALL_BUILD_DIRS_FROM_ROOT = model.transform_string_list( ALL_DIRS_FROM_ROOT, ':', '', '/' + TMP_BSC_DIR) ALL_LIB_DIRS_FROM_ROOT = ALL_DIRS_FROM_ROOT + ':' + ALL_BUILD_DIRS_FROM_ROOT # Due to the bluespec linker, for LI second pass builds, the final # verilog link step must occur in a different directory than the # bsc object code wrapper compilation step. However, non-LIM # linker builds need to build in the original .bsc directory to # pick up VPI. vexe_vdir = moduleList.env['DEFS'][ 'ROOT_DIR_HW'] + '/' + moduleList.env['DEFS'][ 'ROOT_DIR_MODEL'] + '/' + moduleList.env['DEFS']['TMP_BSC_DIR'] if (not self.firstPassLIGraph is None): vexe_vdir = vexe_vdir + '_vlog' if not os.path.isdir(vexe_vdir): os.mkdir(vexe_vdir) LI_LINK_DIR = "" if (not self.firstPassLIGraph is None): LI_LINK_DIR = model.get_build_path(moduleList, moduleList.topModule) + "/.li/" inc_paths += [LI_LINK_DIR] ALL_LIB_DIRS_FROM_ROOT = LI_LINK_DIR + ':' + ALL_LIB_DIRS_FROM_ROOT liCodeType = [ 'VERILOG', 'GIVEN_VERILOG_HS', 'GEN_VPI_CS', 'GEN_VPI_HS' ] # This can be refactored as a function. if (not self.firstPassLIGraph is None): for moduleName in self.firstPassLIGraph.modules: moduleObject = self.firstPassLIGraph.modules[moduleName] # we also need the module list object moduleListObject = moduleList.modules[moduleName] for codeType in liCodeType: # If we're linking, clean out any previous code dependencies. These are guaranteed not to be used. moduleListObject.moduleDependency[codeType] = [] li_module.linkFirstPassObject(moduleList, moduleListObject, self.firstPassLIGraph, codeType, codeType, linkDirectory=vexe_vdir) bsc_version = bsv_tool.getBluespecVersion() ldflags = '' for ld_file in moduleList.getAllDependenciesWithPaths( 'GIVEN_BLUESIM_LDFLAGSS'): ldHandle = open( moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + ld_file, 'r') ldflags += ldHandle.read() + ' ' BSC_FLAGS_VERILOG = '-steps 10000000 +RTS -K1000M -RTS -keep-fires -aggressive-conditions -wait-for-license -no-show-method-conf -no-opt-bool -licenseWarning 7 -elab -show-schedule ' + ldflags + ' -verilog -v -vsim iverilog ' # Build in parallel. n_jobs = moduleList.env.GetOption('num_jobs') if (bsc_version >= 30006): BSC_FLAGS_VERILOG += '-parallel-sim-link ' + str(n_jobs) + ' ' for path in inc_paths: BSC_FLAGS_VERILOG += ' -I ' + path + ' ' #+ '-Xv -I' + path + ' ' LDFLAGS = moduleList.env['DEFS']['LDFLAGS'] TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ROOT_WRAPPER_SYNTH_ID = 'mk_' + moduleList.env['DEFS'][ 'ROOT_DIR_MODEL'] + '_Wrapper' vexe_gen_command = \ BSC + ' ' + BSC_FLAGS_VERILOG + ' -vdir ' + vexe_vdir + ' -simdir ' + vexe_vdir + ' -bdir ' + vexe_vdir +' -p +:' + ALL_LIB_DIRS_FROM_ROOT + ' -vsearch +:' + ALL_LIB_DIRS_FROM_ROOT + ' ' + \ ' -o $TARGET' if (bsc_version >= 13013): # 2008.01.A compiler allows us to pass C++ arguments. if (model.getDebug(moduleList)): vexe_gen_command += ' -Xc++ -O0' else: vexe_gen_command += ' -Xc++ -O1' # g++ 4.5.2 is complaining about overflowing the var tracking table if (model.getGccVersion() >= 40501): vexe_gen_command += ' -Xc++ -fno-var-tracking-assignments' defs = (software_tool.host_defs()).split(" ") for definition in defs: vexe_gen_command += ' -Xc++ ' + definition + ' -Xc ' + definition # Hack to link against pthreads. Really we should have a better solution. vexe_gen_command += ' -Xl -lpthread ' # construct full path to BAs def modify_path(str): array = str.split('/') file = array.pop() return moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + '/'.join( array) + '/' + TMP_BSC_DIR + '/' + file # Use systemverilog 2005 if (moduleList.getAWBParam('verilog_tool', 'ENABLE_SYSTEM_VERILOG')): vexe_gen_command += ' -Xv -g2005-sv ' # Allow .vh/.sv file extensions etc. # vexe_gen_command += ' -Xv -Y.vh -Xv -Y.sv ' # Bluespec requires that source files terminate the command line. vexe_gen_command += '-verilog -e ' + ROOT_WRAPPER_SYNTH_ID + ' ' +\ moduleList.env['DEFS']['BDPI_CS'] if (model.getBuildPipelineDebug(moduleList) != 0): for m in moduleList.getAllDependencies('BA'): print 'BA dep: ' + str(m) for m in moduleList.getAllDependencies('VERILOG'): print 'VL dep: ' + str(m) for m in moduleList.getAllDependencies('VHDL'): print 'BA dep: ' + str(m) # Generate a thin wrapper around the verilog executable. This # wrapper is used to address a problem in iverilog in which the # simulator does not support shared library search paths. The # current wrapper only works for iverilog. Due to brokeness in # the iverilog argument parser, we must construct a correct # iverilog command line by analyzing its compiled script. Also, # this script is not passing through the arguments that it should # be passing through. def generate_vexe_wrapper(target, source, env): wrapper_handle = open(str(target[0]), 'w') wrapper_handle.write('#!/usr/bin/perl\n') wrapper_handle.write('# generated by verilog.py\n') wrapper_handle.write('$platform = $ENV{"PLATFORM_DIRECTORY"};\n') wrapper_handle.write('@script = `cat $platform/' + TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe' + '`;\n') wrapper_handle.write('$script[0] =~ s/#!/ /g;\n') wrapper_handle.write('$vvp = $script[0];\n') wrapper_handle.write('chomp($vvp);\n') wrapper_handle.write( 'exec("$vvp -m$platform/directc_mk_model_Wrapper.so $platform/' + TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe' + ' +bscvcd \$* ");\n') wrapper_handle.close() def modify_path_ba_local(path): return bsv_tool.modify_path_ba(moduleList, path) # Bluesim builds apparently touch this code. This control block # preserves their behavior, but it is unclear why the verilog build is # involved. if (isPrimaryBuildTarget): vbinDeps = [] # If we got a lim graph, we'll pick up many of our dependencies from it. # These were annotated in the top module above. Really, this seems unclean. # we should build a graph during the second pass and just use it. if (not self.firstPassLIGraph is None): # Collect linked dependencies for every module for moduleName in self.firstPassLIGraph.modules: moduleListObject = moduleList.modules[moduleName] vbinDeps += moduleList.getDependencies( moduleListObject, 'VERILOG') + moduleList.getDependencies( moduleListObject, 'GIVEN_VERILOG_HS') + moduleList.getDependencies( moduleListObject, 'GEN_VPI_HS') + moduleList.getDependencies( moduleListObject, 'GEN_VPI_CS') + moduleList.getDependencies( moduleListObject, 'VHDL') + moduleList.getDependencies( moduleListObject, 'BA') + moduleList.getDependencies( moduleListObject, 'GEN_BAS') vbinDeps += moduleList.getDependencies( moduleList.topModule, 'VERILOG') + moduleList.getDependencies( moduleList.topModule, 'GIVEN_VERILOG_HS') + moduleList.getDependencies( moduleList.topModule, 'GEN_VPI_HS') + moduleList.getDependencies( moduleList.topModule, 'GEN_VPI_CS' ) + moduleList.getDependencies( moduleList.topModule, 'VHDL' ) + moduleList.getDependencies( moduleList.topModule, 'BA') + map( modify_path_ba_local, moduleList.getModuleDependenciesWithPaths( moduleList.topModule, 'GEN_BAS')) # collect dependencies from all awb modules else: vbinDeps += moduleList.getAllDependencies( 'VERILOG') + moduleList.getAllDependencies( 'VHDL') + moduleList.getAllDependencies('BA') + map( modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')) vbin = moduleList.env.Command( TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe', vbinDeps, [vexe_gen_command, SCons.Script.Delete('directc.sft')]) vexe = moduleList.env.Command(APM_NAME + '_hw.exe', vbin, [ generate_vexe_wrapper, '@chmod a+x $TARGET', SCons.Script.Delete(APM_NAME + '_hw.errinfo') ]) moduleList.topDependency = moduleList.topDependency + [vexe] else: vbinDeps = moduleList.getAllDependencies( 'VERILOG') + moduleList.getAllDependencies( 'VHDL') + moduleList.getAllDependencies('BA') + map( modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')) vbin = moduleList.env.Command( TMP_BSC_DIR + '/' + APM_NAME + '_hw.vexe', vbinDeps, [vexe_gen_command, SCons.Script.Delete('directc.sft')]) vexe = moduleList.env.Command(APM_NAME + '_hw.vexe', vbin, [ generate_vexe_wrapper, '@chmod a+x $TARGET', SCons.Script.Delete(APM_NAME + '_hw.exe'), SCons.Script.Delete(APM_NAME + '_hw.errinfo') ]) moduleList.env.Alias('vexe', vexe)
def __init__(self, moduleList): env = moduleList.env tree_base_path = env.Dir( model.get_build_path(moduleList, moduleList.topModule)) # get rid of this at some point - since we know we're in # bluesim, we should be able to do the right thing. APM_NAME = moduleList.env['DEFS']['APM_NAME'] BSC = moduleList.env['DEFS']['BSC'] inc_paths = moduleList.swIncDir # we need to depend on libasim bsc_version = bsv_tool.getBluespecVersion() ldflags = '' for ld_file in moduleList.getAllDependenciesWithPaths( 'GIVEN_BLUESIM_LDFLAGSS'): ldHandle = open( moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + ld_file, 'r') ldflags += ldHandle.read() + ' ' BSC_FLAGS_SIM = '-steps 10000000 +RTS -K1000M -RTS -keep-fires -aggressive-conditions -wait-for-license -no-show-method-conf -no-opt-bool -licenseWarning 7 -elab -show-schedule -l pthread ' + ldflags + ' ' # Build in parallel. n_jobs = moduleList.env.GetOption('num_jobs') if (bsc_version >= 30006): BSC_FLAGS_SIM += '-parallel-sim-link ' + str(n_jobs) + ' ' for path in inc_paths: BSC_FLAGS_SIM += '-I ' + path + ' ' LDFLAGS = moduleList.env['DEFS']['LDFLAGS'] TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ROOT_WRAPPER_SYNTH_ID = 'mk_' + moduleList.env['DEFS'][ 'ROOT_DIR_MODEL'] + '_Wrapper' all_hw_dirs = [ env.Dir(d) for d in moduleList.env['DEFS']['ALL_HW_DIRS'].split(':') ] all_build_dirs = [d.Dir(TMP_BSC_DIR) for d in all_hw_dirs] ALL_DIRS_FROM_ROOT = ':'.join([d.path for d in all_hw_dirs]) ALL_BUILD_DIRS_FROM_ROOT = ':'.join([d.path for d in all_build_dirs]) ALL_LIB_DIRS_FROM_ROOT = ALL_DIRS_FROM_ROOT + ':' + ALL_BUILD_DIRS_FROM_ROOT bsc_sim_command = BSC + ' ' + BSC_FLAGS_SIM + ' ' + LDFLAGS + ' ' + ldflags + ' -o $TARGET' # Set MAKEFLAGS because Bluespec is going to invoke make on its own and # we don't want to pass on the current build's recursive flags. bsc_sim_command = 'env MAKEFLAGS="-j ' + str( n_jobs) + '" ' + bsc_sim_command if (bsc_version >= 13013): # 2008.01.A compiler allows us to pass C++ arguments. if (model.getDebug(moduleList)): bsc_sim_command += ' -Xc++ -O0' else: bsc_sim_command += ' -Xc++ -O1' # g++ 4.5.2 is complaining about overflowing the var tracking table if (model.getGccVersion() >= 40501): bsc_sim_command += ' -Xc++ -fno-var-tracking-assignments' defs = (software_tool.host_defs()).split(" ") for definition in defs: bsc_sim_command += ' -Xc++ ' + definition + ' -Xc ' + definition def modify_path_bdpi(path): return moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + path def modify_path_ba_local(path): return bsv_tool.modify_path_ba(moduleList, path) LI_LINK_DIR = "" if (not (wrapper_gen_tool.getFirstPassLIGraph()) is None): LI_LINK_DIR = tree_base_path.Dir('.li').path bdpi_cs = [ env.File(c) for c in moduleList.env['DEFS']['BDPI_CS'].split(' ') ] BDPI_CS = ' '.join([c.path for c in bdpi_cs]) bsc_sim_command += \ ' -sim -e ' + ROOT_WRAPPER_SYNTH_ID + ' -p +:' + LI_LINK_DIR + ':' + ALL_LIB_DIRS_FROM_ROOT +' -simdir ' + \ TMP_BSC_DIR + ' ' +\ ' ' + BDPI_CS if (model.getBuildPipelineDebug(moduleList) != 0): print "BLUESIM DEPS: \n" for ba in moduleList.getAllDependencies('BA'): print 'Bluesim BA dep: ' + str(ba) + '\n' for ba in map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GIVEN_BAS')): print 'Bluesim GIVEN_BA dep: ' + str(ba) + '\n' for ba in map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')): print 'Bluesim GEN_BA dep: ' + str(ba) + '\n' sbin_name = TMP_BSC_DIR + '/' + APM_NAME sbin = moduleList.env.Command( sbin_name + '_hw.exe', moduleList.getAllDependencies('BA') + map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GIVEN_BAS')) + map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')) + map(modify_path_bdpi, moduleList.getAllDependenciesWithPaths('GIVEN_BDPI_CS')) + map(modify_path_bdpi, moduleList.getAllDependenciesWithPaths('GIVEN_BDPI_HS')), bsc_sim_command) if moduleList.env.GetOption('clean'): os.system('rm -rf .bsc') # If we have bsc data files, copy them over to the .bsc directory if len(moduleList.getAllDependencies('GEN_VS')) > 0: Copy(TMP_BSC_DIR, moduleList.getAllDependencies('GIVEN_DATAS')) # # The final step must leave a few well known names: # APM_NAME must be the software side, if there is one. If there isn't, then # it must be the Bluesim image. # if (model.getBuildPipelineDebug(moduleList) != 0): print "ModuleList desp : " + str(moduleList.swExe) exe = moduleList.env.Command(APM_NAME, sbin, [ '@ln -fs ' + sbin_name + '_hw.exe ${TARGET}_hw.exe', '@ln -fs ' + sbin_name + '_hw.exe.so ${TARGET}_hw.exe.so', '@ln -fs ' + moduleList.swExeOrTarget + ' ${TARGET}', SCons.Script.Delete('${TARGET}_hw.vexe'), SCons.Script.Delete('${TARGET}_hw.errinfo') ]) moduleList.topDependency = moduleList.topDependency + [exe]
def __init__(self, moduleList): env = moduleList.env tree_base_path = env.Dir(model.get_build_path(moduleList, moduleList.topModule)) # get rid of this at some point - since we know we're in # bluesim, we should be able to do the right thing. APM_NAME = moduleList.env['DEFS']['APM_NAME'] BSC = moduleList.env['DEFS']['BSC'] inc_paths = moduleList.swIncDir # we need to depend on libasim bsc_version = bsv_tool.getBluespecVersion() ldflags = '' for ld_file in moduleList.getAllDependenciesWithPaths('GIVEN_BLUESIM_LDFLAGSS'): ldHandle = open(moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + ld_file, 'r') ldflags += ldHandle.read() + ' ' BSC_FLAGS_SIM = '-steps 10000000 +RTS -K1000M -RTS -keep-fires -aggressive-conditions -wait-for-license -no-show-method-conf -no-opt-bool -licenseWarning 7 -elab -show-schedule -l pthread ' + ldflags + ' ' # Build in parallel. n_jobs = moduleList.env.GetOption('num_jobs') if (bsc_version >= 30006): BSC_FLAGS_SIM += '-parallel-sim-link ' + str(n_jobs) + ' ' for path in inc_paths: BSC_FLAGS_SIM += '-I ' + path + ' ' LDFLAGS = moduleList.env['DEFS']['LDFLAGS'] TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ROOT_WRAPPER_SYNTH_ID = 'mk_' + moduleList.env['DEFS']['ROOT_DIR_MODEL'] + '_Wrapper' all_hw_dirs = [env.Dir(d) for d in moduleList.env['DEFS']['ALL_HW_DIRS'].split(':')] all_build_dirs = [d.Dir(TMP_BSC_DIR) for d in all_hw_dirs] ALL_DIRS_FROM_ROOT = ':'.join([d.path for d in all_hw_dirs]) ALL_BUILD_DIRS_FROM_ROOT = ':'.join([d.path for d in all_build_dirs]) ALL_LIB_DIRS_FROM_ROOT = ALL_DIRS_FROM_ROOT + ':' + ALL_BUILD_DIRS_FROM_ROOT bsc_sim_command = BSC + ' ' + BSC_FLAGS_SIM + ' ' + LDFLAGS + ' ' + ldflags + ' -o $TARGET' # Set MAKEFLAGS because Bluespec is going to invoke make on its own and # we don't want to pass on the current build's recursive flags. bsc_sim_command = 'env MAKEFLAGS="-j ' + str(n_jobs) + '" ' + bsc_sim_command if (bsc_version >= 13013): # 2008.01.A compiler allows us to pass C++ arguments. if (model.getDebug(moduleList)): bsc_sim_command += ' -Xc++ -O0' else: bsc_sim_command += ' -Xc++ -O1' # g++ 4.5.2 is complaining about overflowing the var tracking table if (model.getGccVersion() >= 40501): bsc_sim_command += ' -Xc++ -fno-var-tracking-assignments' defs = (software_tool.host_defs()).split(" ") for definition in defs: bsc_sim_command += ' -Xc++ ' + definition + ' -Xc ' + definition def modify_path_bdpi(path): return moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + path def modify_path_ba_local(path): return bsv_tool.modify_path_ba(moduleList, path) LI_LINK_DIR = "" if (not (wrapper_gen_tool.getFirstPassLIGraph()) is None): LI_LINK_DIR = tree_base_path.Dir('.li').path bdpi_cs = [env.File(c) for c in moduleList.env['DEFS']['BDPI_CS'].split(' ')] BDPI_CS = ' '.join([c.path for c in bdpi_cs]) bsc_sim_command += \ ' -sim -e ' + ROOT_WRAPPER_SYNTH_ID + ' -p +:' + LI_LINK_DIR + ':' + ALL_LIB_DIRS_FROM_ROOT +' -simdir ' + \ TMP_BSC_DIR + ' ' +\ ' ' + BDPI_CS if (model.getBuildPipelineDebug(moduleList) != 0): print "BLUESIM DEPS: \n" for ba in moduleList.getAllDependencies('BA'): print 'Bluesim BA dep: ' + str(ba) + '\n' for ba in map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GIVEN_BAS')): print 'Bluesim GIVEN_BA dep: ' + str(ba) + '\n' for ba in map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')): print 'Bluesim GEN_BA dep: ' + str(ba) + '\n' sbin_name = TMP_BSC_DIR + '/' + APM_NAME sbin = moduleList.env.Command( sbin_name + '_hw.exe', moduleList.getAllDependencies('BA') + map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GIVEN_BAS')) + map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')) + map(modify_path_bdpi, moduleList.getAllDependenciesWithPaths('GIVEN_BDPI_CS')) + map(modify_path_bdpi, moduleList.getAllDependenciesWithPaths('GIVEN_BDPI_HS')), bsc_sim_command) if moduleList.env.GetOption('clean'): os.system('rm -rf .bsc') # If we have bsc data files, copy them over to the .bsc directory if len(moduleList.getAllDependencies('GEN_VS'))> 0: Copy(TMP_BSC_DIR, moduleList.getAllDependencies('GIVEN_DATAS')) # # The final step must leave a few well known names: # APM_NAME must be the software side, if there is one. If there isn't, then # it must be the Bluesim image. # if (model.getBuildPipelineDebug(moduleList) != 0): print "ModuleList desp : " + str(moduleList.swExe) exe = moduleList.env.Command( APM_NAME, sbin, [ '@ln -fs ' + sbin_name + '_hw.exe ${TARGET}_hw.exe', '@ln -fs ' + sbin_name + '_hw.exe.so ${TARGET}_hw.exe.so', '@ln -fs ' + moduleList.swExeOrTarget + ' ${TARGET}', SCons.Script.Delete('${TARGET}_hw.vexe'), SCons.Script.Delete('${TARGET}_hw.errinfo') ]) moduleList.topDependency = moduleList.topDependency + [exe]
def __init__(self, moduleList, isPrimaryBuildTarget): APM_NAME = moduleList.env['DEFS']['APM_NAME'] BSC = moduleList.env['DEFS']['BSC'] inc_paths = moduleList.swIncDir # we need to depend on libasim self.firstPassLIGraph = wrapper_gen_tool.getFirstPassLIGraph() # This is not correct for LIM builds and needs to be fixed. TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ALL_DIRS_FROM_ROOT = moduleList.env['DEFS']['ALL_HW_DIRS'] ALL_BUILD_DIRS_FROM_ROOT = model.transform_string_list(ALL_DIRS_FROM_ROOT, ':', '', '/' + TMP_BSC_DIR) ALL_INC_DIRS_FROM_ROOT = '-Xv +incdir+' + ALL_DIRS_FROM_ROOT.replace(':','+') #insert any supplied include paths for incdir in moduleList.getAllDependencies('VERILOG_INC_DIRS'): ALL_INC_DIRS_FROM_ROOT += "+" + incdir ALL_LIB_DIRS_FROM_ROOT = ALL_DIRS_FROM_ROOT + ':' + ALL_BUILD_DIRS_FROM_ROOT # Due to the bluespec linker, for LI second pass builds, the final # verilog link step must occur in a different directory than the # bsc object code wrapper compilation step. However, non-LIM # linker builds need to build in the original .bsc directory to # pick up VPI. vexe_vdir = moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + moduleList.env['DEFS']['ROOT_DIR_MODEL'] + '/' + moduleList.env['DEFS']['TMP_BSC_DIR'] if(not self.firstPassLIGraph is None): vexe_vdir = vexe_vdir + '_vlog' if not os.path.isdir(vexe_vdir): os.mkdir(vexe_vdir) LI_LINK_DIR = "" if (not self.firstPassLIGraph is None): LI_LINK_DIR = model.get_build_path(moduleList, moduleList.topModule) + "/.li/" inc_paths += [LI_LINK_DIR] ALL_LIB_DIRS_FROM_ROOT = LI_LINK_DIR + ':' + ALL_LIB_DIRS_FROM_ROOT liCodeType = ['VERILOG_PKG', 'VERILOG', 'GIVEN_VERILOG_HS', 'GEN_VPI_CS', 'GEN_VPI_HS'] # This can be refactored as a function. if (not self.firstPassLIGraph is None): for moduleName in self.firstPassLIGraph.modules: moduleObject = self.firstPassLIGraph.modules[moduleName] for codeType in liCodeType: if(codeType in moduleObject.objectCache): for verilog in moduleObject.objectCache[codeType]: linkPath = vexe_vdir + '/' + os.path.basename(verilog) moduleList.env.Command(linkPath, verilog, model.link_file) if(codeType in moduleList.topModule.moduleDependency): moduleList.topModule.moduleDependency[codeType] += [linkPath] else: moduleList.topModule.moduleDependency[codeType] = [linkPath] else: # Warn that we did not find the ngc we expected to find.. print "Warning: We did not find verilog for module " + moduleName bsc_version = bsv_tool.getBluespecVersion() ldflags = '' for ld_file in moduleList.getAllDependenciesWithPaths('GIVEN_BLUESIM_LDFLAGSS'): ldHandle = open(moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + ld_file, 'r') ldflags += ldHandle.read() + ' ' BSC_FLAGS_VERILOG = '-steps 10000000 +RTS -K1000M -RTS -keep-fires -aggressive-conditions -wait-for-license -no-show-method-conf -no-opt-bool -licenseWarning 7 -elab -show-schedule ' + ldflags + ' -verilog -v -vsim vcs ' # Build in parallel. n_jobs = moduleList.env.GetOption('num_jobs') if (bsc_version >= 30006): BSC_FLAGS_VERILOG += '-parallel-sim-link ' + str(n_jobs) + ' ' for path in inc_paths: BSC_FLAGS_VERILOG += ' -I ' + path + ' ' LDFLAGS = moduleList.env['DEFS']['LDFLAGS'] TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ROOT_WRAPPER_SYNTH_ID = 'mk_' + moduleList.env['DEFS']['ROOT_DIR_MODEL'] + '_Wrapper' vexe_gen_command = \ BSC + ' ' + BSC_FLAGS_VERILOG + ' -vdir ' + vexe_vdir + ' -simdir ' + vexe_vdir + ' -bdir ' + vexe_vdir +' -p +:' + ALL_LIB_DIRS_FROM_ROOT + ' -vsearch +:' + ALL_LIB_DIRS_FROM_ROOT + ' ' + \ ' -o $TARGET' if (bsc_version >= 13013): # 2008.01.A compiler allows us to pass C++ arguments. if (model.getDebug(moduleList)): vexe_gen_command += ' -Xc++ -O0' else: vexe_gen_command += ' -Xc++ -O1' # g++ 4.5.2 is complaining about overflowing the var tracking table if (model.getGccVersion() >= 40501): vexe_gen_command += ' -Xc++ -fno-var-tracking-assignments' defs = (software_tool.host_defs()).split(" ") for definition in defs: vexe_gen_command += ' -Xc++ ' + definition + ' -Xc ' + definition # cflags to be passed into vcs compiler for definition in defs: vexe_gen_command += ' -Xv -CFLAGS -Xv ' + definition for path in inc_paths: vexe_gen_command += ' -Xv -CFLAGS -Xv -I' + path for lib in moduleList.swLinkLibs: vexe_gen_command += ' -Xl -l' + lib + ' ' vexe_gen_command += ' -Xv -LDFLAGS -Xv -l' + lib + ' ' # construct full path to BAs def modify_path(str): array = str.split('/') file = array.pop() return moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + '/'.join(array) + '/' + TMP_BSC_DIR + '/' + file if (moduleList.getAWBParam('verilog_tool', 'VCS_ENABLE_LINT') != 0): vexe_gen_command += ' -Xv +lint=all,noVCDE' vexe_gen_command += ' -Xv -full64 ' vexe_gen_command += ' -Xv -sverilog ' vexe_gen_command += ' -Xv +librescan ' vexe_gen_command += ' -Xv +libext+.sv ' if (moduleList.getAWBParam('verilog_tool', 'VCS_ARGUMENTS')): vexe_gen_command += moduleList.getAWBParam('verilog_tool', 'VCS_ARGUMENTS') vexe_gen_command += ' ' + ALL_INC_DIRS_FROM_ROOT + ' ' # VCS must be informed of all BDPI. Really we need some kind of # file object here. All this massaging of path is ridiculous. vexe_gen_command += ' -Xv ' + moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + (' -Xv ' + moduleList.env['DEFS']['ROOT_DIR_HW'] + '/').join(moduleList.getAllDependenciesWithPaths('GIVEN_BDPI_CS')) + ' ' # Bluespec requires that source files terminate the command line. vexe_gen_command += ' -verilog -e ' + ROOT_WRAPPER_SYNTH_ID + ' ' +\ moduleList.env['DEFS']['BDPI_CS'] vexe_gen_command += ' ' + ' '.join(moduleList.getAllDependencies('VERILOG_PKG')) vexe_gen_command += ' ' + ' '.join(moduleList.getAllDependencies('VERILOG')) vexe_gen_command += ' ' + ' '.join(moduleList.getAllDependencies('VHDL')) if (model.getBuildPipelineDebug(moduleList) != 0): for m in moduleList.getAllDependencies('BA'): print 'BA dep: ' + str(m) for m in moduleList.getAllDependencies('VERILOG_PKG'): print 'VPKG dep: ' + str(m) for m in moduleList.getAllDependencies('VERILOG'): print 'VL dep: ' + str(m) for m in moduleList.getAllDependencies('VHDL'): print 'BA dep: ' + str(m) for m in moduleList.getAllDependencies('GIVEN_BDPI_CS'): print 'GIVEN_BDPI_CS: ' + str(m) # Generate a thin wrapper around the verilog executable. This # wrapper is used to address a problem in iverilog in which the # simulator does not support shared library search paths. The # current wrapper only works for iverilog. Due to brokeness in # the iverilog argument parser, we must construct a correct # iverilog command line by analyzing its compiled script. Also, # this script is not passing through the arguments that it should # be passing through. def generate_vexe_wrapper(target, source, env): wrapper_handle = open(str(target[0]),'w') wrapper_handle.write('#!/usr/bin/perl\n') wrapper_handle.write('# generated by verilog.py\n') wrapper_handle.write('$platform = $ENV{"PLATFORM_DIRECTORY"};\n') wrapper_handle.write('$ENV{LD_LIBRARY_PATH} = $platform . ":" . $ENV{LD_LIBRARY_PATH};\n') wrapper_handle.write('`ln -sf $platform/directc_mk_model_Wrapper.so .`;\n') wrapper_handle.write('exec("$platform/' + TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe -licqueue \$* ");\n') wrapper_handle.close() def modify_path_ba_local(path): return bsv_tool.modify_path_ba(moduleList, path) # Bluesim builds apparently touch this code. This control block # preserves their behavior, but it is unclear why the verilog build is # involved. if (isPrimaryBuildTarget): vbinDeps = [] # If we got a lim graph, we'll pick up many of our dependencies from it. # These were annotated in the top module above. Really, this seems unclean. # we should build a graph during the second pass and just use it. if(not self.firstPassLIGraph is None): vbinDeps += moduleList.getDependencies(moduleList.topModule, 'VERILOG_PKG') + \ moduleList.getDependencies(moduleList.topModule, 'VERILOG') + \ moduleList.getDependencies(moduleList.topModule, 'VERILOG_LIB') + \ moduleList.getDependencies(moduleList.topModule, 'GIVEN_VERILOG_HS') + \ moduleList.getDependencies(moduleList.topModule, 'GEN_VPI_HS') + \ moduleList.getDependencies(moduleList.topModule, 'GEN_VPI_CS') + \ moduleList.getDependencies(moduleList.topModule, 'VHDL') + \ moduleList.getDependencies(moduleList.topModule, 'BA') + \ map(modify_path_ba_local, moduleList.getModuleDependenciesWithPaths(moduleList.topModule, 'GEN_BAS')) # collect dependencies from all awb modules else: vbinDeps += moduleList.getAllDependencies('VERILOG_PKG') + \ moduleList.getAllDependencies('VERILOG') + \ moduleList.getAllDependencies('VERILOG_LIB') + \ moduleList.getAllDependencies('VHDL') + \ moduleList.getAllDependencies('BA') + \ map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')) vbin = moduleList.env.Command( TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe', vbinDeps, [ vexe_gen_command ]) moduleList.env.AlwaysBuild(vbin) vexe = moduleList.env.Command( APM_NAME + '_hw.exe', vbin, [ generate_vexe_wrapper, '@chmod a+x $TARGET', SCons.Script.Delete(APM_NAME + '_hw.errinfo') ]) moduleList.topDependency = moduleList.topDependency + [vexe] else: vbin = moduleList.env.Command( TMP_BSC_DIR + '/' + APM_NAME + '_hw.vexe', moduleList.getAllDependencies('VERILOG_PKG') + moduleList.getAllDependencies('VERILOG') + moduleList.getAllDependencies('VHDL') + moduleList.getAllDependencies('BA') + map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')), [ vexe_gen_command ]) vexe = moduleList.env.Command( APM_NAME + '_hw.vexe', vbin, [ generate_vexe_wrapper, '@chmod a+x $TARGET', SCons.Script.Delete(APM_NAME + '_hw.exe'), SCons.Script.Delete(APM_NAME + '_hw.errinfo') ]) moduleList.env.Alias('vexe', vexe)
def __init__(self, moduleList): # some definitions used during the bsv compilation process env = moduleList.env self.moduleList = moduleList self.hw_dir = env.Dir(moduleList.env['DEFS']['ROOT_DIR_HW']) self.TMP_BSC_DIR = env['DEFS']['TMP_BSC_DIR'] synth_modules = moduleList.synthBoundaries() self.USE_TREE_BUILD = moduleList.getAWBParam('wrapper_gen_tool', 'USE_BUILD_TREE') # all_module_dirs: a list of all module directories in the build tree self.all_module_dirs = [ self.hw_dir.Dir(moduleList.topModule.buildPath) ] for module in synth_modules: if (module.buildPath != moduleList.topModule.buildPath): self.all_module_dirs += [self.hw_dir.Dir(module.buildPath)] # all_build_dirs: the build (.bsc) sub-directory of all module directories self.all_build_dirs = [ d.Dir(self.TMP_BSC_DIR) for d in self.all_module_dirs ] # Include iface directories self.all_module_dirs += iface_tool.getIfaceIncludeDirs(moduleList) self.all_build_dirs += iface_tool.getIfaceLibDirs(moduleList) # Add the top level build directory self.all_build_dirs += [env.Dir(self.TMP_BSC_DIR)] self.all_module_dirs += [ self.hw_dir.Dir('include'), self.hw_dir.Dir('include/awb/provides') ] # Full search path: all module and build directories self.all_lib_dirs = self.all_module_dirs + self.all_build_dirs all_build_dir_paths = [d.path for d in self.all_build_dirs] self.ALL_BUILD_DIR_PATHS = ':'.join(all_build_dir_paths) all_lib_dir_paths = [d.path for d in self.all_lib_dirs] self.ALL_LIB_DIR_PATHS = ':'.join(all_lib_dir_paths) # we need to annotate the module list with the # bluespec-provided library files. Do so here. bsv_tool.decorateBluespecLibraryCode(moduleList) self.TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] self.BUILD_LOGS_ONLY = moduleList.getAWBParam('bsv_tool', 'BUILD_LOGS_ONLY') self.USE_BVI = moduleList.getAWBParam('bsv_tool', 'USE_BVI') self.pipeline_debug = model.getBuildPipelineDebug(moduleList) # Should we be building in events? if (model.getEvents(moduleList) == 0): bsc_events_flag = ' -D HASIM_EVENTS_ENABLED=False ' else: bsc_events_flag = ' -D HASIM_EVENTS_ENABLED=True ' self.BSC_FLAGS = moduleList.getAWBParam('bsv_tool', 'BSC_FLAGS') + bsc_events_flag moduleList.env.VariantDir(self.TMP_BSC_DIR, '.', duplicate=0) moduleList.env['ENV']['BUILD_DIR'] = moduleList.env['DEFS'][ 'BUILD_DIR'] # need to set the builddir for synplify topo = moduleList.topologicalOrderSynth() topo.reverse() # Cleaning? Wipe out module temporary state. Do this before # the topo pop to ensure that we don't leave garbage around at # the top level. if moduleList.env.GetOption('clean'): for module in topo: MODULE_PATH = get_build_path(moduleList, module) os.system('cd ' + MODULE_PATH + '/' + self.TMP_BSC_DIR + '; rm -f *.ba *.c *.h *.sched *.log *.v *.bo *.str') topo.pop() # get rid of top module. ## Python module that generates a wrapper to connect the exposed ## wires of all synthesis boundaries. tree_builder = bsv_tool.BSVSynthTreeBuilder(self) ## ## Is this a normal build or a build in which only Bluespec dependence ## is computed? ## if not moduleList.isDependsBuild: ## ## Normal build. ## ## ## Now that the "depends-init" build is complete we can ## continue with accurate inter-Bluespec file dependence. ## This build only takes place for the first pass object ## code generation. If the first pass li graph exists, it ## subsumes awb-style synthesis boundary generation. ## for module in topo: self.build_synth_boundary(moduleList, module) ## We are going to have a whole bunch of BA and V files coming. ## We don't yet know what they contain, but we do know that there ## will be |synth_modules| - 2 of them if (not 'GEN_VERILOGS' in moduleList.topModule.moduleDependency): moduleList.topModule.moduleDependency['GEN_VERILOGS'] = [] if (not 'GEN_BAS' in moduleList.topModule.moduleDependency): moduleList.topModule.moduleDependency['GEN_BAS'] = [] ## Having described the new build tree dependencies we can build ## the top module. self.build_synth_boundary(moduleList, moduleList.topModule) ## Merge all synthesis boundaries using a tree? The tree reduces ## the number of connections merged in a single compilation, allowing ## us to support larger systems. if self.USE_TREE_BUILD: tree_builder.setupTreeBuild(moduleList, topo) ## ## Generate the global string table. Bluespec-generated global ## strings are stored in files by the compiler. ## ## The global string file will be generated in the top-level ## .bsc directory and a link to it will be added to the ## top-level directory. ## all_str_src = [] #for module in topo + [moduleList.topModule]: for module in moduleList.moduleList + topo + [ moduleList.topModule ]: if ('STR' in module.moduleDependency): all_str_src.extend(module.moduleDependency['STR']) if (self.BUILD_LOGS_ONLY == 0): bsc_str = moduleList.env.Command( self.TMP_BSC_DIR + '/' + moduleList.env['DEFS']['APM_NAME'] + '.str', all_str_src, ['cat $SOURCES > $TARGET']) strDep = moduleList.env.Command( moduleList.env['DEFS']['APM_NAME'] + '.str', bsc_str, [ 'ln -fs ' + self.TMP_BSC_DIR + '/`basename $TARGET` $TARGET' ]) moduleList.topDependency += [strDep] if moduleList.env.GetOption('clean'): print 'Cleaning depends-init...' s = os.system('scons --clean depends-init') else: ## ## Dependence build. The target of this build is "depens-init". No ## Bluespec modules will be compiled in this invocation of SCons. ## Only .depends-bsv files will be produced. ## # We need to calculate some dependencies for the build # tree. We could be clever and put this code somewhere # rather than replicate it. if self.USE_TREE_BUILD: buildTreeDeps = {} buildTreeDeps['GEN_VERILOGS'] = [] buildTreeDeps['GEN_BAS'] = [] #This is sort of a hack. buildTreeDeps['WRAPPER_BSHS'] = [ 'awb/provides/soft_services.bsh' ] buildTreeDeps['GIVEN_BSVS'] = [] buildTreeDeps['BA'] = [] buildTreeDeps['STR'] = [] buildTreeDeps['VERILOG'] = [] buildTreeDeps['BSV_LOG'] = [] buildTreeDeps['VERILOG_STUB'] = [] tree_module = Module( 'build_tree', ["mkBuildTree"], moduleList.topModule.buildPath,\ moduleList.topModule.name,\ [], moduleList.topModule.name, [], buildTreeDeps, platformModule=True) tree_module.dependsFile = '.depends-build-tree' moduleList.insertModule(tree_module) tree_file_bo = get_build_path( moduleList, moduleList.topModule) + "/build_tree.bsv" # sprinkle files to get dependencies right bo_handle = open(tree_file_bo, 'w') # mimic AWB/leap-configure bo_handle.write('//\n') bo_handle.write( '// Synthesized compilation file for module: build_tree\n') bo_handle.write('//\n') bo_handle.write('// This file was created by BSV.py\n') bo_handle.write('//\n') bo_handle.write('`define BUILDING_MODULE_build_tree\n') bo_handle.write('`include "build_tree_Wrapper.bsv"\n') bo_handle.close() # Calling generateWrapperStub will write out default _Wrapper.bsv # and _Log.bsv files for build tree. However, these files # may already exists, and, in the case of build_tree_Wrapper.bsv, # have meaningful content. Fortunately, generateWrapperStub # will not over write existing files. wrapper_gen_tool.generateWrapperStub(moduleList, tree_module) wrapper_gen_tool.generateAWBCompileWrapper( moduleList, tree_module) topo.append(tree_module) deps = [] useDerived = True first_pass_LI_graph = wrapper_gen_tool.getFirstPassLIGraph() if (not first_pass_LI_graph is None): useDerived = False # we also need to parse the platform_synth file in th platform_synth = get_build_path( moduleList, moduleList.topModule ) + "/" + moduleList.localPlatformName + "_platform_synth.bsv" platform_deps = ".depends-platform" deps += self.compute_dependence(moduleList, moduleList.topModule, useDerived, fileName=platform_deps, targetFiles=[platform_synth]) # If we have an LI graph, we need to construct and compile # several LI wrappers. do that here. # include all the dependencies in the graph in the wrapper. li_wrappers = [] tree_base_path = get_build_path(moduleList, moduleList.topModule) liGraph = LIGraph([]) firstPassGraph = first_pass_LI_graph # We should ignore the 'PLATFORM_MODULE' liGraph.mergeModules([ module for module in getUserModules(firstPassGraph) if module.getAttribute('RESYNTHESIZE') is None ]) for module in sorted(liGraph.graph.nodes(), key=lambda module: module.name): wrapper_import_path = tree_base_path + '/' + module.name + '_Wrapper.bsv' li_wrappers.append(module.name + '_Wrapper.bsv') wrapper_import_handle = open(wrapper_import_path, 'w') wrapper_import_handle.write('import Vector::*;\n') wrapper_gen_tool.generateWellKnownIncludes( wrapper_import_handle) wrapper_gen_tool.generateBAImport(module, wrapper_import_handle) wrapper_import_handle.close() platform_deps = ".depends-" + module.name deps += self.compute_dependence( moduleList, moduleList.topModule, useDerived, fileName=platform_deps, targetFiles=[wrapper_import_path]) for module in topo + [moduleList.topModule]: # for object import builds no Wrapper code will be included. remove it. deps += self.compute_dependence(moduleList, module, useDerived, fileName=module.dependsFile) moduleList.topDependsInit += deps
def __init__(self, moduleList): TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] topModulePath = get_build_path(moduleList, moduleList.topModule) # The LIM compiler uniquifies synthesis boundary names uidOffset = int(moduleList.getAWBParam('wrapper_gen_tool', 'MODULE_UID_OFFSET')) # We only inject the platform wrapper in first pass builds. In # the second pass, we import the first pass object code. It may # be that we need this code? # Inject a synth boundary for platform build code. we need to # pick up some dependencies from the top level code. this is a # pretty major hack, in my opinion. Better would be to actually # inspect the eventual .ba files for their dependencies. platformName = moduleList.localPlatformName + '_platform' platformDeps = {} platformDeps['GEN_VERILOGS'] = [] platformDeps['GEN_BAS'] = [] #moduleList.getSynthBoundaryDependencies(moduleList.topModule, 'GEN_BAS') platformDeps['GEN_VPI_HS'] = moduleList.getSynthBoundaryDependencies(moduleList.topModule, 'GEN_VPI_HS') platformDeps['GEN_VPI_CS'] = moduleList.getSynthBoundaryDependencies(moduleList.topModule, 'GEN_VPI_CS') #This is sort of a hack. platformDeps['GIVEN_BSVS'] = [] platformDeps['WRAPPER_BSHS'] = ['awb/provides/virtual_platform.bsh', 'awb/provides/physical_platform.bsh'] platformDeps['BA'] = [] platformDeps['STR'] = [] platformDeps['VERILOG'] = [topModulePath + '/' + TMP_BSC_DIR + '/mk_' + platformName + '_Wrapper.v'] platformDeps['BSV_LOG'] = [] platformDeps['VERILOG_STUB'] = [] platform_module = Module( platformName, ["mkVirtualPlatform"], moduleList.topModule.buildPath,\ moduleList.topModule.name,\ [], moduleList.topModule.name, [], platformDeps, platformModule=True) platform_module.dependsFile = '.depends-platform' platform_module.interfaceType = 'VIRTUAL_PLATFORM' platform_module.extraImports = ['virtual_platform'] first_pass_LI_graph = getFirstPassLIGraph() if(first_pass_LI_graph is None): moduleList.insertModule(platform_module) moduleList.graphize() moduleList.graphizeSynth() # Sprinkle more files expected by the two-pass build. generateWrapperStub(moduleList, platform_module) generateAWBCompileWrapper(moduleList, platform_module) else: platform_module_li = first_pass_LI_graph.modules[moduleList.localPlatformName + '_platform'] # This gives us the right path. synthHandle = getSynthHandle(moduleList, platform_module) # throw in some includes... synthHandle.write('import HList::*;\n') synthHandle.write('import Vector::*;\n') synthHandle.write('import ModuleContext::*;\n') synthHandle.write('import GetPut::*;\n') synthHandle.write('import Clocks::*;\n') synthHandle.write('`include "awb/provides/virtual_platform.bsh"\n') synthHandle.write('`include "awb/provides/physical_platform.bsh"\n') generateWellKnownIncludes(synthHandle) # May need an extra import here? # get the platform module from the LIGraph generateBAImport(platform_module_li, synthHandle) # include synth stub here.... _emitSynthModule(platform_module_li, synthHandle, platform_module.interfaceType, localPlatformName = moduleList.localPlatformName) ## Here we use a module list sorted alphabetically in order to guarantee ## the generated wrapper files are consistent. The topological sort ## guarantees only a depth first traversal -- not the same traversal ## each time. synth_modules = [moduleList.topModule] + moduleList.synthBoundaries() ## Models have the option of declaring top-level clocks that will ## be exposed as arguments. When top-level clocks exist a single ## top-level reset is also defined. To request no top-level clocks ## the variable N_TOP_LEVEL_CLOCKS should be removed from a platform's ## AWB configuration file, since Bluespec can't test the value of ## a preprocessor variable. try: n_top_clocks = int(moduleList.getAWBParam('physical_platform', 'N_TOP_LEVEL_CLOCKS')) if (n_top_clocks == 0): sys.stderr.write("Error: N_TOP_LEVEL_CLOCKS may not be 0 due to Bluespec preprocessor\n") sys.stderr.write(" limitations. To eliminate top-level clocks, remove the AWB\n") sys.stderr.write(" parameter from the platform configuration.\n") sys.exit(1) except: n_top_clocks = 0 for module in synth_modules: modPath = moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + module.buildPath + '/' + module.name wrapperPath = modPath + "_Wrapper.bsv" logPath = modPath + "_Log.bsv" conSizePath = modPath + "_Wrapper_con_size.bsh" ignorePath = moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + module.buildPath + '/.ignore' # clear out code on clean. if moduleList.env.GetOption('clean'): os.system('rm -f ' + wrapperPath) os.system('rm -f ' + logPath) os.system('rm -f ' + conSizePath) os.system('rm -f ' + ignorePath) if (module.name != moduleList.topModule.name): os.system('rm -f ' + modPath + '.bsv') continue if (model.getBuildPipelineDebug(moduleList) != 0): print "Wrapper path is " + wrapperPath wrapper_bsv = open(wrapperPath, 'w') ignore_bsv = open(ignorePath, 'w') ignore_bsv.write("// Generated by wrapper_gen.py\n\n") # Connection size doesn't appear on the first dependence pass, since it # doesn't exist until after the first build. Finding it later results in # build dependence changes and rebuilding. Ignore it, since the file will # change only when some other file changes. ignore_bsv.write(conSizePath) ignore_bsv.close() # Generate a dummy connection size file to avoid errors during dependence # analysis. if not os.path.exists(conSizePath): dummyModule = LIModule(module.name, module.name) bsh_handle = open(conSizePath, 'w') generateConnectionBSH(dummyModule, bsh_handle) bsh_handle.close() wrapper_bsv.write('import HList::*;\n') wrapper_bsv.write('import Vector::*;\n') wrapper_bsv.write('import ModuleContext::*;\n') # the top module is handled specially if (module.name == moduleList.topModule.name): generateWellKnownIncludes(wrapper_bsv) wrapper_bsv.write('// These are well-known/required leap modules\n') wrapper_bsv.write('// import non-synthesis public files\n') # Include all subordinate synthesis boundaries for use by # instantiateAllSynthBoundaries() below. # If we're doing a LIM build, there are no *_synth.bsv for use codes. # Probably if we're doing a build tree they aren't necessary either, but # removing those dependencies would take a little work. if(first_pass_LI_graph is None): for synth in synth_modules: if synth != module: wrapper_bsv.write('`include "' + synth.name + '_synth.bsv"\n') # Provide a method that imports all subordinate synthesis # boundaries. It will be invoked inside the top level model # in order to build all soft connections use_build_tree = moduleList.getAWBParam('wrapper_gen_tool', 'USE_BUILD_TREE') expose_all_connections = 0 try: expose_all_connections = moduleList.getAWBParam('model', 'EXPOSE_ALL_CONNECTIONS') except: pass if (use_build_tree == 1): wrapper_bsv.write('\n\n`ifdef CONNECTION_SIZES_KNOWN\n'); # build_tree.bsv will get generated later, during the # leap-connect phase. wrapper_bsv.write(' import build_tree_synth::*;\n'); wrapper_bsv.write(' module [Connected_Module] instantiateAllSynthBoundaries#(Reset baseReset) ();\n') wrapper_bsv.write(' Reset rst <- mkResetFanout(baseReset);\n') wrapper_bsv.write(' let m <- build_tree(baseReset, reset_by rst);\n') wrapper_bsv.write(' endmodule\n') wrapper_bsv.write('`else\n'); wrapper_bsv.write('\n module ') if len(synth_modules) != 1: wrapper_bsv.write('[Connected_Module]') wrapper_bsv.write(' instantiateAllSynthBoundaries#(Reset baseReset) ();\n') for synth in synth_modules: if synth != module and not synth.platformModule: wrapper_bsv.write(' ' + synth.synthBoundaryModule + '();\n') wrapper_bsv.write(' endmodule\n') if (use_build_tree == 1): wrapper_bsv.write('`endif\n'); # Import platform wrapper. wrapper_bsv.write(' import ' + moduleList.localPlatformName +'_platform_synth::*;\n'); wrapper_bsv.write(' module [Connected_Module] instantiatePlatform ('+ platform_module.interfaceType +');\n') wrapper_bsv.write(' let m <- ' + moduleList.localPlatformName + '_platform(noReset);\n') wrapper_bsv.write(' return m;\n') wrapper_bsv.write(' endmodule\n') wrapper_bsv.write('`include "' + module.name + '.bsv"\n') wrapper_bsv.write('\n// import non-synthesis private files\n') wrapper_bsv.write('// Get defintion of TOP_LEVEL_WIRES\n') wrapper_bsv.write('import physical_platform::*;\n') wrapper_bsv.write('(* synthesize *)\n') wrapper_bsv.write('module [Module] mk_model_Wrapper\n') wrapper_bsv.write(' (TOP_LEVEL_WIRES);\n\n') wrapper_bsv.write(' // Instantiate main module\n') wrapper_bsv.write(' let m <- mkModel(clocked_by noClock, reset_by noReset);\n') wrapper_bsv.write(' return m;\n') wrapper_bsv.write('endmodule\n') else: log_bsv = open(logPath, 'w') log_bsv.write('import HList::*;\n') log_bsv.write('import ModuleContext::*;\n') # Parents of a synthesis boundary likely import the top level module of # the boundary. This way, the synthesis boundary could be removed and # the code within the boundary would be imported correctly by the parent. # The code within the synthesis boundary will actually be imported at the # top level instead, so we need a dummy module for use by the parent of # a boundary that looks like it imports the code but actually does nothing. # Importing at the top level allows us to build all synthesis regions # in parallel. dummy_import_bsv = open(modPath + '.bsv', 'w') dummy_import_bsv.write('// Generated by wrapper_gen.py\n\n') dummy_import_bsv.write('module ' + module.synthBoundaryModule + ' ();\n'); dummy_import_bsv.write('endmodule\n'); dummy_import_bsv.close() if not os.path.exists(modPath + '_synth.bsv'): dummy_module = LIModule(module.name, module.name) handle = getSynthHandle(moduleList, module) generateSynthWrapper(dummy_module, handle, moduleList.localPlatformName, moduleType = module.interfaceType, extraImports = module.extraImports) for wrapper in [wrapper_bsv, log_bsv]: wrapper.write('// These are well-known/required leap modules\n') generateWellKnownIncludes(wrapper) wrapper.write('`include "awb/provides/librl_bsv_base.bsh"\n') wrapper.write('// import non-synthesis public files\n') wrapper.write('`include "' + module.name + '_compile.bsv"\n') wrapper.write('\n\n') log_bsv.write('// First pass to see how large the vectors should be\n') log_bsv.write('`define CON_RECV_' + module.boundaryName + ' 100\n') log_bsv.write('`define CON_SEND_' + module.boundaryName + ' 100\n') log_bsv.write('`define CON_RECV_MULTI_' + module.boundaryName + ' 50\n') log_bsv.write('`define CON_SEND_MULTI_' + module.boundaryName + ' 50\n') log_bsv.write('`define CHAINS_' + module.boundaryName + ' 50\n') wrapper_bsv.write('// Real build pass. Include file built dynamically.\n') wrapper_bsv.write('`include "' + module.name + '_Wrapper_con_size.bsh"\n') for wrapper in [wrapper_bsv, log_bsv]: wrapper.write('(* synthesize *)\n') wrapper.write('module [Module] ' + module.wrapperName() + '#(Reset baseReset) (SOFT_SERVICES_SYNTHESIS_BOUNDARY#(`CON_RECV_' + module.boundaryName + ', `CON_SEND_' + module.boundaryName + ', `CON_RECV_MULTI_' + module.boundaryName + ', `CON_SEND_MULTI_' + module.boundaryName +', `CHAINS_' + module.boundaryName +', ' + module.interfaceType + '));\n') wrapper.write(' \n') # we need to insert the fpga platform here # get my parameters wrapper.write(' // instantiate own module\n') wrapper.write(' let int_ctx0 <- initializeServiceContext();\n') wrapper.write(' match {.int_ctx1, .int_name1} <- runWithContext(int_ctx0, putSynthesisBoundaryID(fpgaNumPlatforms() + ' + str(module.synthBoundaryUID + uidOffset) + '));\n'); wrapper.write(' match {.int_ctx2, .int_name2} <- runWithContext(int_ctx1, putSynthesisBoundaryPlatform("' + moduleList.localPlatformName + '"));\n') wrapper.write(' match {.int_ctx3, .int_name3} <- runWithContext(int_ctx2, putSynthesisBoundaryPlatformID(' + str(moduleList.localPlatformUID) + '));\n') wrapper.write(' match {.int_ctx4, .int_name4} <- runWithContext(int_ctx3, putSynthesisBoundaryName("' + str(module.boundaryName) + '"));\n') wrapper.write(' // By convention, global string ID 0 (the first string) is the module name\n'); wrapper.write(' match {.int_ctx5, .int_name5} <- runWithContext(int_ctx4, getGlobalStringUID("' + moduleList.localPlatformName + ':' + module.name + '"));\n'); wrapper.write(' match {.int_ctx6, .module_ifc} <- runWithContext(int_ctx5, ' + module.synthBoundaryModule + ');\n') # Need to expose clocks of the platform Module if(module.platformModule): wrapper.write(' match {.clk, .rst} = extractClocks(module_ifc);\n') wrapper.write(' match {.int_ctx7, .int_name7} <- runWithContext(int_ctx6, mkSoftConnectionDebugInfo(clocked_by clk, reset_by rst));\n') wrapper.write(' match {.final_ctx, .m_final} <- runWithContext(int_ctx7, mkSoftConnectionLatencyInfo(clocked_by clk, reset_by rst));\n') else: wrapper.write(' match {.int_ctx7, .int_name7} <- runWithContext(int_ctx6, mkSoftConnectionDebugInfo);\n') wrapper.write(' match {.final_ctx, .m_final} <- runWithContext(int_ctx7, mkSoftConnectionLatencyInfo);\n') wrapper.write(' let service_ifc <- exposeServiceContext(final_ctx);\n') wrapper.write(' interface services = service_ifc;\n') wrapper.write(' interface device = module_ifc;\n') wrapper.write('endmodule\n') log_bsv.close() wrapper_bsv.close()
def compute_dependence(self, moduleList, module, useDerived, fileName='.depends-bsv', targetFiles=[]): MODULE_PATH = get_build_path(moduleList, module) #allow caller to override dependencies. If the caller does #not, then we should use the baseline if (len(targetFiles) == 0): targetFiles = [ moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + module.buildPath + '/' + model.get_wrapper(module) ] if (module.name != moduleList.topModule.name): targetFiles.append(moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + module.buildPath + '/'+ model.get_log(module)) # We must depend on all sythesis boundaries. They can be instantiated anywhere. surrogate_children = moduleList.synthBoundaries() SURROGATE_BSVS = '' for child in surrogate_children: # Make sure module doesn't self-depend if (child.name != module.name): SURROGATE_BSVS += moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + child.buildPath +'/' + child.name + '.bsv ' if (useDerived and SURROGATE_BSVS != ''): DERIVED = ' -derived "' + SURROGATE_BSVS + '"' else: DERIVED = '' depends_bsv = MODULE_PATH + '/' + fileName moduleList.env.NoCache(depends_bsv) compile_deps = 'leap-bsc-mkdepend -ignore ' + MODULE_PATH + '/.ignore' + ' -bdir ' + self.TMP_BSC_DIR + DERIVED + ' -p +:' + self.ALL_LIB_DIR_PATHS + ' ' + ' '.join(targetFiles) + ' > ' + depends_bsv # Delete depends_bsv if it is empty under the assumption that something # went wrong when creating it. An empty dependence file would never be # rebuilt without this. try: if (os.path.getsize(depends_bsv) == 0): os.unlink(depends_bsv) except: None dep = moduleList.env.Command(depends_bsv, targetFiles + moduleList.topModule.moduleDependency['IFACE_HEADERS'], compile_deps) # Load an old .depends-bsv file if it exists. The file describes # the previous dependence among Bluespec files, giving a clue of whether # anything changed. The file describes dependence between derived objects # and sources. Here, we need to know about all possible source changes. # Scan the file looking for source file names. if os.path.isfile(depends_bsv): df = open(depends_bsv, 'r') dep_lines = df.readlines() # Match .bsv and .bsh files bsv_file_pattern = re.compile('\S+.[bB][sS][vVhH]$') all_bsc_files = [] for ln in dep_lines: all_bsc_files += [f for f in re.split('[:\s]+', ln) if (bsv_file_pattern.match(f))] # Sort dependence in case SCons cares for f in sorted(all_bsc_files): if os.path.exists(f): moduleList.env.Depends(dep, f) df.close() return dep
def __init__(self, moduleList, isPrimaryBuildTarget): # if we have a deps build, don't do anything... if(moduleList.isDependsBuild): return APM_NAME = moduleList.env['DEFS']['APM_NAME'] BSC = moduleList.env['DEFS']['BSC'] inc_paths = moduleList.swIncDir # we need to depend on libasim self.firstPassLIGraph = wrapper_gen_tool.getFirstPassLIGraph() # This is not correct for LIM builds and needs to be fixed. TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ALL_DIRS_FROM_ROOT = moduleList.env['DEFS']['ALL_HW_DIRS'] ALL_BUILD_DIRS_FROM_ROOT = model.transform_string_list(ALL_DIRS_FROM_ROOT, ':', '', '/' + TMP_BSC_DIR) ALL_LIB_DIRS_FROM_ROOT = ALL_DIRS_FROM_ROOT + ':' + ALL_BUILD_DIRS_FROM_ROOT # Due to the bluespec linker, for LI second pass builds, the final # verilog link step must occur in a different directory than the # bsc object code wrapper compilation step. However, non-LIM # linker builds need to build in the original .bsc directory to # pick up VPI. vexe_vdir = moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + moduleList.env['DEFS']['ROOT_DIR_MODEL'] + '/' + moduleList.env['DEFS']['TMP_BSC_DIR'] if(not self.firstPassLIGraph is None): vexe_vdir = vexe_vdir + '_vlog' if not os.path.isdir(vexe_vdir): os.mkdir(vexe_vdir) LI_LINK_DIR = "" if (not self.firstPassLIGraph is None): LI_LINK_DIR = model.get_build_path(moduleList, moduleList.topModule) + "/.li/" inc_paths += [LI_LINK_DIR] ALL_LIB_DIRS_FROM_ROOT = LI_LINK_DIR + ':' + ALL_LIB_DIRS_FROM_ROOT liCodeType = ['VERILOG', 'GIVEN_VERILOG_HS', 'GEN_VPI_CS', 'GEN_VPI_HS'] # This can be refactored as a function. if (not self.firstPassLIGraph is None): for moduleName in self.firstPassLIGraph.modules: moduleObject = self.firstPassLIGraph.modules[moduleName] # we also need the module list object moduleListObject = moduleList.modules[moduleName] for codeType in liCodeType: # If we're linking, clean out any previous code dependencies. These are guaranteed not to be used. moduleListObject.moduleDependency[codeType] = [] li_module.linkFirstPassObject(moduleList, moduleListObject, self.firstPassLIGraph, codeType, codeType, linkDirectory=vexe_vdir) bsc_version = bsv_tool.getBluespecVersion() ldflags = '' for ld_file in moduleList.getAllDependenciesWithPaths('GIVEN_BLUESIM_LDFLAGSS'): ldHandle = open(moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + ld_file, 'r') ldflags += ldHandle.read() + ' ' BSC_FLAGS_VERILOG = '-steps 10000000 +RTS -K1000M -RTS -keep-fires -aggressive-conditions -wait-for-license -no-show-method-conf -no-opt-bool -licenseWarning 7 -elab -show-schedule ' + ldflags + ' -verilog -v -vsim iverilog ' # Build in parallel. n_jobs = moduleList.env.GetOption('num_jobs') if (bsc_version >= 30006): BSC_FLAGS_VERILOG += '-parallel-sim-link ' + str(n_jobs) + ' ' for path in inc_paths: BSC_FLAGS_VERILOG += ' -I ' + path + ' ' #+ '-Xv -I' + path + ' ' LDFLAGS = moduleList.env['DEFS']['LDFLAGS'] TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] ROOT_WRAPPER_SYNTH_ID = 'mk_' + moduleList.env['DEFS']['ROOT_DIR_MODEL'] + '_Wrapper' vexe_gen_command = \ BSC + ' ' + BSC_FLAGS_VERILOG + ' -vdir ' + vexe_vdir + ' -simdir ' + vexe_vdir + ' -bdir ' + vexe_vdir +' -p +:' + ALL_LIB_DIRS_FROM_ROOT + ' -vsearch +:' + ALL_LIB_DIRS_FROM_ROOT + ' ' + \ ' -o $TARGET' if (bsc_version >= 13013): # 2008.01.A compiler allows us to pass C++ arguments. if (model.getDebug(moduleList)): vexe_gen_command += ' -Xc++ -O0' else: vexe_gen_command += ' -Xc++ -O1' # g++ 4.5.2 is complaining about overflowing the var tracking table if (model.getGccVersion() >= 40501): vexe_gen_command += ' -Xc++ -fno-var-tracking-assignments' defs = (software_tool.host_defs()).split(" ") for definition in defs: vexe_gen_command += ' -Xc++ ' + definition + ' -Xc ' + definition # Hack to link against pthreads. Really we should have a better solution. vexe_gen_command += ' -Xl -lpthread ' # construct full path to BAs def modify_path(str): array = str.split('/') file = array.pop() return moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + '/'.join(array) + '/' + TMP_BSC_DIR + '/' + file # Use systemverilog 2005 if(moduleList.getAWBParam('verilog_tool', 'ENABLE_SYSTEM_VERILOG')): vexe_gen_command += ' -Xv -g2005-sv ' # Allow .vh/.sv file extensions etc. # vexe_gen_command += ' -Xv -Y.vh -Xv -Y.sv ' # Bluespec requires that source files terminate the command line. vexe_gen_command += '-verilog -e ' + ROOT_WRAPPER_SYNTH_ID + ' ' +\ moduleList.env['DEFS']['BDPI_CS'] if (model.getBuildPipelineDebug(moduleList) != 0): for m in moduleList.getAllDependencies('BA'): print 'BA dep: ' + str(m) for m in moduleList.getAllDependencies('VERILOG'): print 'VL dep: ' + str(m) for m in moduleList.getAllDependencies('VHDL'): print 'BA dep: ' + str(m) # Generate a thin wrapper around the verilog executable. This # wrapper is used to address a problem in iverilog in which the # simulator does not support shared library search paths. The # current wrapper only works for iverilog. Due to brokeness in # the iverilog argument parser, we must construct a correct # iverilog command line by analyzing its compiled script. Also, # this script is not passing through the arguments that it should # be passing through. def generate_vexe_wrapper(target, source, env): wrapper_handle = open(str(target[0]),'w') wrapper_handle.write('#!/usr/bin/perl\n') wrapper_handle.write('# generated by verilog.py\n') wrapper_handle.write('$platform = $ENV{"PLATFORM_DIRECTORY"};\n') wrapper_handle.write('@script = `cat $platform/' + TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe' + '`;\n') wrapper_handle.write('$script[0] =~ s/#!/ /g;\n') wrapper_handle.write('$vvp = $script[0];\n') wrapper_handle.write('chomp($vvp);\n') wrapper_handle.write('exec("$vvp -m$platform/directc_mk_model_Wrapper.so $platform/' + TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe' + ' +bscvcd \$* ");\n') wrapper_handle.close() def modify_path_ba_local(path): return bsv_tool.modify_path_ba(moduleList, path) # Bluesim builds apparently touch this code. This control block # preserves their behavior, but it is unclear why the verilog build is # involved. if (isPrimaryBuildTarget): vbinDeps = [] # If we got a lim graph, we'll pick up many of our dependencies from it. # These were annotated in the top module above. Really, this seems unclean. # we should build a graph during the second pass and just use it. if(not self.firstPassLIGraph is None): # Collect linked dependencies for every module for moduleName in self.firstPassLIGraph.modules: moduleListObject = moduleList.modules[moduleName] vbinDeps += moduleList.getDependencies(moduleListObject, 'VERILOG') + moduleList.getDependencies(moduleListObject, 'GIVEN_VERILOG_HS') + moduleList.getDependencies(moduleListObject, 'GEN_VPI_HS') + moduleList.getDependencies(moduleListObject, 'GEN_VPI_CS') + moduleList.getDependencies(moduleListObject, 'VHDL') + moduleList.getDependencies(moduleListObject, 'BA') + moduleList.getDependencies(moduleListObject, 'GEN_BAS') vbinDeps += moduleList.getDependencies(moduleList.topModule, 'VERILOG') + moduleList.getDependencies(moduleList.topModule, 'GIVEN_VERILOG_HS') + moduleList.getDependencies(moduleList.topModule, 'GEN_VPI_HS') + moduleList.getDependencies(moduleList.topModule, 'GEN_VPI_CS') +moduleList.getDependencies(moduleList.topModule, 'VHDL') + moduleList.getDependencies(moduleList.topModule, 'BA') + map(modify_path_ba_local, moduleList.getModuleDependenciesWithPaths(moduleList.topModule, 'GEN_BAS')) # collect dependencies from all awb modules else: vbinDeps += moduleList.getAllDependencies('VERILOG') + moduleList.getAllDependencies('VHDL') + moduleList.getAllDependencies('BA') + map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')) vbin = moduleList.env.Command( TMP_BSC_DIR + '/' + APM_NAME + '_hw.exe', vbinDeps, [ vexe_gen_command, SCons.Script.Delete('directc.sft') ]) vexe = moduleList.env.Command( APM_NAME + '_hw.exe', vbin, [ generate_vexe_wrapper, '@chmod a+x $TARGET', SCons.Script.Delete(APM_NAME + '_hw.errinfo') ]) moduleList.topDependency = moduleList.topDependency + [vexe] else: vbinDeps = moduleList.getAllDependencies('VERILOG') + moduleList.getAllDependencies('VHDL') + moduleList.getAllDependencies('BA') + map(modify_path_ba_local, moduleList.getAllDependenciesWithPaths('GEN_BAS')) vbin = moduleList.env.Command( TMP_BSC_DIR + '/' + APM_NAME + '_hw.vexe', vbinDeps, [ vexe_gen_command, SCons.Script.Delete('directc.sft') ]) vexe = moduleList.env.Command( APM_NAME + '_hw.vexe', vbin, [ generate_vexe_wrapper, '@chmod a+x $TARGET', SCons.Script.Delete(APM_NAME + '_hw.exe'), SCons.Script.Delete(APM_NAME + '_hw.errinfo') ]) moduleList.env.Alias('vexe', vexe)
def build_synth_boundary(self, moduleList, module): if (self.pipeline_debug != 0): print "Working on " + module.name env = moduleList.env BSVS = moduleList.getSynthBoundaryDependencies(module, 'GIVEN_BSVS') # each submodel will have a generated BSV GEN_BSVS = moduleList.getSynthBoundaryDependencies(module, 'GEN_BSVS') APM_FILE = moduleList.env['DEFS']['APM_FILE'] BSC = moduleList.env['DEFS']['BSC'] MODULE_PATH = get_build_path(moduleList, module) ## ## Load intra-Bluespec dependence already computed. This information will ## ultimately drive the building of Bluespec modules. ## env.ParseDepends(MODULE_PATH + '/' + module.dependsFile, must_exist = not moduleList.env.GetOption('clean')) # This function is responsible for creating build rules for # subdirectories. It must be called or no subdirectory builds # will happen since scons won't have the recipe. self.setup_module_build(moduleList, MODULE_PATH) if not os.path.isdir(self.TMP_BSC_DIR): os.mkdir(self.TMP_BSC_DIR) moduleList.env.VariantDir(MODULE_PATH + '/' + self.TMP_BSC_DIR, '.', duplicate=0) # set up builds for the various bsv of this synthesis # boundary. One wonders if we could handle this as a single # global operation. bsc_builds = [] for bsv in BSVS + GEN_BSVS: bsc_builds += env.BSC(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', ''), MODULE_PATH + '/' + bsv) firstPassLIGraph = wrapper_gen_tool.getFirstPassLIGraph() # In the second pass of the LIM build, we don't need to build # any modules, except in some cases where we turn on # module-specific optimizations, as in the case of central # cache. If we do need to rebuild, we'll see a tag. if ((module.name != moduleList.topModule.name) and (not firstPassLIGraph is None) and (module.name in firstPassLIGraph.modules) and (firstPassLIGraph.modules[module.name].getAttribute('RESYNTHESIZE') is None)): return # This should not be a for loop. for bsv in [model.get_wrapper(module)]: if env.GetOption('clean'): os.system('rm -f ' + MODULE_PATH + '/' + bsv.replace('Wrapper.bsv', 'Log.bsv')) os.system('rm -f ' + MODULE_PATH + '/' + bsv.replace('.bsv', '_con_size.bsh')) ## ## First pass just generates a log file to figure out cross synthesis ## boundary soft connection array sizes. ## ## All but the top level build need the log build pass to compute ## the size of the external soft connection vector. The top level has ## no exposed connections and can generate the log file, needed ## for global strings, during the final build. ## logfile = model.get_logfile(moduleList, module) module.moduleDependency['BSV_LOG'] += [logfile] module.moduleDependency['GEN_LOGS'] = [logfile] if (module.name != moduleList.topModule.name): log = env.BSC_LOG_ONLY(logfile, MODULE_PATH + '/' + bsv.replace('Wrapper.bsv', 'Log')) ## ## Parse the log, generate a stub file ## stub_name = bsv.replace('.bsv', '_con_size.bsh') def build_con_size_bsh_closure(target, source, env): liGraph = LIGraph(li_module.parseLogfiles(source)) # Should have only one module... if(len(liGraph.modules) == 0): bshModule = LIModule(module.name, module.name) else: bshModule = liGraph.modules.values()[0] bsh_handle = open(str(target[0]), 'w') wrapper_gen_tool.generateConnectionBSH(bshModule, bsh_handle) bsh_handle.close() stub = env.Command(MODULE_PATH + '/' + stub_name, log, build_con_size_bsh_closure) ## ## Now we are ready for the real build ## if (module.name != moduleList.topModule.name): wrapper_bo = env.BSC(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', ''), MODULE_PATH + '/' + bsv) moduleList.env.Depends(wrapper_bo, stub) module.moduleDependency['BO'] = [wrapper_bo] if (self.BUILD_LOGS_ONLY): model_dir = self.hw_dir.Dir(moduleList.env['DEFS']['ROOT_DIR_MODEL']) module.moduleDependency['BSV_SCHED'] = \ [moduleList.env.Command(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.ba.sched', wrapper_bo, 'bluetcl ' + model_dir.File('sched.tcl').path + ' -p ' + self.ALL_BUILD_DIR_PATHS + ' --m ' + module.wrapperName() + ' > $TARGET')] module.moduleDependency['BSV_PATH'] = \ [moduleList.env.Command(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.ba.path', wrapper_bo, 'bluetcl ' + model_dir.File('path.tcl').path + ' -p ' + self.ALL_BUILD_DIR_PATHS + ' --m ' + module.wrapperName() + ' > $TARGET')] moduleList.topDependency += \ module.moduleDependency['BSV_SCHED'] + module.moduleDependency['BSV_PATH'] module.moduleDependency['BSV_IFC'] = \ [moduleList.env.Command(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.ba.ifc', wrapper_bo, 'bluetcl ' + model_dir.File('interfaceType.tcl').path + ' -p ' + self.ALL_BUILD_DIR_PATHS + ' --m ' + module.wrapperName() + ' | python site_scons/model/PythonTidy.py > $TARGET')] moduleList.topDependency += module.moduleDependency['BSV_IFC'] else: ## Top level build can generate the log in a single pass since no ## connections are exposed wrapper_bo = env.BSC_LOG(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', ''), MODULE_PATH + '/' + bsv) ## SCons doesn't deal well with logfile as a 2nd target to BSC_LOG rule, ## failing to derive dependence correctly. module.moduleDependency['BSV_BO'] = [wrapper_bo] log = env.Command(logfile, wrapper_bo, '') env.Precious(logfile) ## In case Bluespec build is the end of the build pipeline. if (not self.BUILD_LOGS_ONLY): moduleList.topDependency += [log] ## The toplevel bo also depends on the on the synthesis of the build tree from log files. ## ## Meta-data written during compilation to separate files. ## glob_str = env.Command(MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', '.str'), wrapper_bo, '') env.Precious(glob_str) module.moduleDependency['STR'] = [glob_str] ## All but the top level build need the log build pass to compute ## the size of the external soft connection vector. The top level has ## no exposed connections and needs no log build pass. ## if (module.name != moduleList.topModule.name): if (self.pipeline_debug != 0): print 'wrapper_bo: ' + str(wrapper_bo) print 'stub: ' + str(stub) synth_stub_path = moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + module.buildPath + '/' synth_stub = synth_stub_path + module.name +'_synth.bsv' # This stub may be needed in certain compilation flows. Note its presence here. module.moduleDependency['BSV_SYNTH'] = [module.name +'_synth.bsv'] module.moduleDependency['BSV_SYNTH_BSH'] = [module.name +'_Wrapper_con_size.bsh'] def build_synth_stub(target, source, env): liGraph = LIGraph(li_module.parseLogfiles(source)) # Should have only one module... if(len(liGraph.modules) == 0): synthModule = LIModule(module.name, module.name) else: synthModule = liGraph.modules.values()[0] synth_handle = open(target[0].path, 'w') wrapper_gen_tool.generateSynthWrapper(synthModule, synth_handle, moduleList.localPlatformName, moduleType=module.interfaceType, extraImports=module.extraImports, synthBoundaryModule = module) synth_handle.close() env.Command(synth_stub, # target logfile, build_synth_stub) ## ## The mk_<wrapper>.v file is really built by the Wrapper() builder ## above. We use NULL commands to convince SCons the file is generated. ## This seems easier than SCons SideEffect() calls, which don't clean ## targets. ## ## We also generate all this synth boundary's GEN_VS ## ext_gen_v = [] for v in moduleList.getSynthBoundaryDependencies(module, 'GEN_VS'): ext_gen_v += [MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + v] # Add the dependence for all Verilog noted above bld_v = env.Command([MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.v'] + ext_gen_v, MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', '.bo'), '') env.Precious(bld_v) if (moduleList.getAWBParam('bsv_tool', 'BUILD_VERILOG') == 1): module.moduleDependency['VERILOG'] += [bld_v] + [ext_gen_v] module.moduleDependency['GEN_WRAPPER_VERILOGS'] = [os.path.basename(module.wrapperName() + '.v')] if (self.pipeline_debug != 0): print "Name: " + module.name # each synth boundary will produce a ba bld_ba = [env.Command([MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + module.wrapperName() + '.ba'], MODULE_PATH + '/' + self.TMP_BSC_DIR + '/' + bsv.replace('.bsv', '.bo'), '')] module.moduleDependency['BA'] += bld_ba env.Precious(bld_ba) ## ## Build the Verilog black-box stub. ## bb = self.stubGenCommand(MODULE_PATH, module.boundaryName, bld_v) # Only the subordinate modules have stubs. # The platform module should not be enumerated here. This is a false dependency. if (module.name != moduleList.topModule.name): moduleList.topModule.moduleDependency['VERILOG_STUB'] += [bb] module.moduleDependency['GEN_VERILOG_STUB'] = [bb] return [bb] #This doesn't seem to do anything.
def __init__(self, moduleList): # some definitions used during the bsv compilation process env = moduleList.env self.moduleList = moduleList self.hw_dir = env.Dir(moduleList.env['DEFS']['ROOT_DIR_HW']) self.TMP_BSC_DIR = env['DEFS']['TMP_BSC_DIR'] synth_modules = moduleList.synthBoundaries() self.USE_TREE_BUILD = moduleList.getAWBParam('wrapper_gen_tool', 'USE_BUILD_TREE') # all_module_dirs: a list of all module directories in the build tree self.all_module_dirs = [self.hw_dir.Dir(moduleList.topModule.buildPath)] for module in synth_modules: if (module.buildPath != moduleList.topModule.buildPath): self.all_module_dirs += [self.hw_dir.Dir(module.buildPath)] # all_build_dirs: the build (.bsc) sub-directory of all module directories self.all_build_dirs = [d.Dir(self.TMP_BSC_DIR) for d in self.all_module_dirs] # Include iface directories self.all_module_dirs += iface_tool.getIfaceIncludeDirs(moduleList) self.all_build_dirs += iface_tool.getIfaceLibDirs(moduleList) # Add the top level build directory self.all_build_dirs += [env.Dir(self.TMP_BSC_DIR)] self.all_module_dirs += [self.hw_dir.Dir('include'), self.hw_dir.Dir('include/awb/provides')] # Full search path: all module and build directories self.all_lib_dirs = self.all_module_dirs + self.all_build_dirs all_build_dir_paths = [d.path for d in self.all_build_dirs] self.ALL_BUILD_DIR_PATHS = ':'.join(all_build_dir_paths) all_lib_dir_paths = [d.path for d in self.all_lib_dirs] self.ALL_LIB_DIR_PATHS = ':'.join(all_lib_dir_paths) # we need to annotate the module list with the # bluespec-provided library files. Do so here. bsv_tool.decorateBluespecLibraryCode(moduleList) self.TMP_BSC_DIR = moduleList.env['DEFS']['TMP_BSC_DIR'] self.BUILD_LOGS_ONLY = moduleList.getAWBParam('bsv_tool', 'BUILD_LOGS_ONLY') self.USE_BVI = moduleList.getAWBParam('bsv_tool', 'USE_BVI') self.pipeline_debug = model.getBuildPipelineDebug(moduleList) # Should we be building in events? if (model.getEvents(moduleList) == 0): bsc_events_flag = ' -D HASIM_EVENTS_ENABLED=False ' else: bsc_events_flag = ' -D HASIM_EVENTS_ENABLED=True ' self.BSC_FLAGS = moduleList.getAWBParam('bsv_tool', 'BSC_FLAGS') + bsc_events_flag moduleList.env.VariantDir(self.TMP_BSC_DIR, '.', duplicate=0) moduleList.env['ENV']['BUILD_DIR'] = moduleList.env['DEFS']['BUILD_DIR'] # need to set the builddir for synplify topo = moduleList.topologicalOrderSynth() topo.reverse() # Cleaning? Wipe out module temporary state. Do this before # the topo pop to ensure that we don't leave garbage around at # the top level. if moduleList.env.GetOption('clean'): for module in topo: MODULE_PATH = get_build_path(moduleList, module) os.system('cd '+ MODULE_PATH + '/' + self.TMP_BSC_DIR + '; rm -f *.ba *.c *.h *.sched *.log *.v *.bo *.str') topo.pop() # get rid of top module. ## Python module that generates a wrapper to connect the exposed ## wires of all synthesis boundaries. tree_builder = bsv_tool.BSVSynthTreeBuilder(self) ## ## Is this a normal build or a build in which only Bluespec dependence ## is computed? ## if not moduleList.isDependsBuild: ## ## Normal build. ## ## ## Now that the "depends-init" build is complete we can ## continue with accurate inter-Bluespec file dependence. ## This build only takes place for the first pass object ## code generation. If the first pass li graph exists, it ## subsumes awb-style synthesis boundary generation. ## for module in topo: self.build_synth_boundary(moduleList, module) ## We are going to have a whole bunch of BA and V files coming. ## We don't yet know what they contain, but we do know that there ## will be |synth_modules| - 2 of them if (not 'GEN_VERILOGS' in moduleList.topModule.moduleDependency): moduleList.topModule.moduleDependency['GEN_VERILOGS'] = [] if (not 'GEN_BAS' in moduleList.topModule.moduleDependency): moduleList.topModule.moduleDependency['GEN_BAS'] = [] ## Having described the new build tree dependencies we can build ## the top module. self.build_synth_boundary(moduleList, moduleList.topModule) ## Merge all synthesis boundaries using a tree? The tree reduces ## the number of connections merged in a single compilation, allowing ## us to support larger systems. if self.USE_TREE_BUILD: tree_builder.setupTreeBuild(moduleList, topo) ## ## Generate the global string table. Bluespec-generated global ## strings are stored in files by the compiler. ## ## The global string file will be generated in the top-level ## .bsc directory and a link to it will be added to the ## top-level directory. ## all_str_src = [] #for module in topo + [moduleList.topModule]: for module in moduleList.moduleList + topo + [moduleList.topModule]: if('STR' in module.moduleDependency): all_str_src.extend(module.moduleDependency['STR']) if (self.BUILD_LOGS_ONLY == 0): bsc_str = moduleList.env.Command(self.TMP_BSC_DIR + '/' + moduleList.env['DEFS']['APM_NAME'] + '.str', all_str_src, [ 'cat $SOURCES > $TARGET']) strDep = moduleList.env.Command(moduleList.env['DEFS']['APM_NAME'] + '.str', bsc_str, [ 'ln -fs ' + self.TMP_BSC_DIR + '/`basename $TARGET` $TARGET' ]) moduleList.topDependency += [strDep] if moduleList.env.GetOption('clean'): print 'Cleaning depends-init...' s = os.system('scons --clean depends-init') else: ## ## Dependence build. The target of this build is "depens-init". No ## Bluespec modules will be compiled in this invocation of SCons. ## Only .depends-bsv files will be produced. ## # We need to calculate some dependencies for the build # tree. We could be clever and put this code somewhere # rather than replicate it. if self.USE_TREE_BUILD: buildTreeDeps = {} buildTreeDeps['GEN_VERILOGS'] = [] buildTreeDeps['GEN_BAS'] = [] #This is sort of a hack. buildTreeDeps['WRAPPER_BSHS'] = ['awb/provides/soft_services.bsh'] buildTreeDeps['GIVEN_BSVS'] = [] buildTreeDeps['BA'] = [] buildTreeDeps['STR'] = [] buildTreeDeps['VERILOG'] = [] buildTreeDeps['BSV_LOG'] = [] buildTreeDeps['VERILOG_STUB'] = [] tree_module = Module( 'build_tree', ["mkBuildTree"], moduleList.topModule.buildPath,\ moduleList.topModule.name,\ [], moduleList.topModule.name, [], buildTreeDeps, platformModule=True) tree_module.dependsFile = '.depends-build-tree' moduleList.insertModule(tree_module) tree_file_bo = get_build_path(moduleList, moduleList.topModule) + "/build_tree.bsv" # sprinkle files to get dependencies right bo_handle = open(tree_file_bo,'w') # mimic AWB/leap-configure bo_handle.write('//\n') bo_handle.write('// Synthesized compilation file for module: build_tree\n') bo_handle.write('//\n') bo_handle.write('// This file was created by BSV.py\n') bo_handle.write('//\n') bo_handle.write('`define BUILDING_MODULE_build_tree\n') bo_handle.write('`include "build_tree_Wrapper.bsv"\n') bo_handle.close() # Calling generateWrapperStub will write out default _Wrapper.bsv # and _Log.bsv files for build tree. However, these files # may already exists, and, in the case of build_tree_Wrapper.bsv, # have meaningful content. Fortunately, generateWrapperStub # will not over write existing files. wrapper_gen_tool.generateWrapperStub(moduleList, tree_module) wrapper_gen_tool.generateAWBCompileWrapper(moduleList, tree_module) topo.append(tree_module) deps = [] useDerived = True first_pass_LI_graph = wrapper_gen_tool.getFirstPassLIGraph() if (not first_pass_LI_graph is None): useDerived = False # we also need to parse the platform_synth file in th platform_synth = get_build_path(moduleList, moduleList.topModule) + "/" + moduleList.localPlatformName + "_platform_synth.bsv" platform_deps = ".depends-platform" deps += self.compute_dependence(moduleList, moduleList.topModule, useDerived, fileName=platform_deps, targetFiles=[platform_synth]) # If we have an LI graph, we need to construct and compile # several LI wrappers. do that here. # include all the dependencies in the graph in the wrapper. li_wrappers = [] tree_base_path = get_build_path(moduleList, moduleList.topModule) liGraph = LIGraph([]) firstPassGraph = first_pass_LI_graph # We should ignore the 'PLATFORM_MODULE' liGraph.mergeModules([ module for module in getUserModules(firstPassGraph) if module.getAttribute('RESYNTHESIZE') is None]) for module in sorted(liGraph.graph.nodes(), key=lambda module: module.name): wrapper_import_path = tree_base_path + '/' + module.name + '_Wrapper.bsv' li_wrappers.append(module.name + '_Wrapper.bsv') wrapper_import_handle = open(wrapper_import_path, 'w') wrapper_import_handle.write('import Vector::*;\n') wrapper_gen_tool.generateWellKnownIncludes(wrapper_import_handle) wrapper_gen_tool.generateBAImport(module, wrapper_import_handle) wrapper_import_handle.close() platform_deps = ".depends-" + module.name deps += self.compute_dependence(moduleList, moduleList.topModule, useDerived, fileName=platform_deps, targetFiles=[wrapper_import_path]) for module in topo + [moduleList.topModule]: # for object import builds no Wrapper code will be included. remove it. deps += self.compute_dependence(moduleList, module, useDerived, fileName=module.dependsFile) moduleList.topDependsInit += deps
def compute_dependence(self, moduleList, module, useDerived, fileName='.depends-bsv', targetFiles=[]): MODULE_PATH = get_build_path(moduleList, module) #allow caller to override dependencies. If the caller does #not, then we should use the baseline if (len(targetFiles) == 0): targetFiles = [ moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + module.buildPath + '/' + model.get_wrapper(module) ] if (module.name != moduleList.topModule.name): targetFiles.append(moduleList.env['DEFS']['ROOT_DIR_HW'] + '/' + module.buildPath + '/' + model.get_log(module)) # We must depend on all sythesis boundaries. They can be instantiated anywhere. surrogate_children = moduleList.synthBoundaries() SURROGATE_BSVS = '' for child in surrogate_children: # Make sure module doesn't self-depend if (child.name != module.name): SURROGATE_BSVS += moduleList.env['DEFS'][ 'ROOT_DIR_HW'] + '/' + child.buildPath + '/' + child.name + '.bsv ' if (useDerived and SURROGATE_BSVS != ''): DERIVED = ' -derived "' + SURROGATE_BSVS + '"' else: DERIVED = '' depends_bsv = MODULE_PATH + '/' + fileName moduleList.env.NoCache(depends_bsv) compile_deps = 'leap-bsc-mkdepend -ignore ' + MODULE_PATH + '/.ignore' + ' -bdir ' + self.TMP_BSC_DIR + DERIVED + ' -p +:' + self.ALL_LIB_DIR_PATHS + ' ' + ' '.join( targetFiles) + ' > ' + depends_bsv # Delete depends_bsv if it is empty under the assumption that something # went wrong when creating it. An empty dependence file would never be # rebuilt without this. try: if (os.path.getsize(depends_bsv) == 0): os.unlink(depends_bsv) except: None dep = moduleList.env.Command( depends_bsv, targetFiles + moduleList.topModule.moduleDependency['IFACE_HEADERS'], compile_deps) # Load an old .depends-bsv file if it exists. The file describes # the previous dependence among Bluespec files, giving a clue of whether # anything changed. The file describes dependence between derived objects # and sources. Here, we need to know about all possible source changes. # Scan the file looking for source file names. if os.path.isfile(depends_bsv): df = open(depends_bsv, 'r') dep_lines = df.readlines() # Match .bsv and .bsh files bsv_file_pattern = re.compile('\S+.[bB][sS][vVhH]$') all_bsc_files = [] for ln in dep_lines: all_bsc_files += [ f for f in re.split('[:\s]+', ln) if (bsv_file_pattern.match(f)) ] # Sort dependence in case SCons cares for f in sorted(all_bsc_files): if os.path.exists(f): moduleList.env.Depends(dep, f) df.close() return dep