def create_scv(self): for constraint in self.constraints: jenv = jinja2.Environment(trim_blocks=True, lstrip_blocks=True) jenv.globals.update(int=int) jenv.loader = jinja2.FileSystemLoader([os.path.dirname(__file__)]) def add_parens_for_vars(cons, cvars): def add_parens(matchobj): if matchobj.group(0) in cvars: return f'{matchobj.group(0)}()' else: return matchobj.group(0) return re.sub(r'([^\d\W]\w*)', add_parens, cons) scv_cons = [ add_parens_for_vars(c, constraint.cvars) for c in constraint.cons ] context = { 'vars': constraint.cvars, 'constraints': scv_cons, 'base_cls': constraint.cls } c = jenv.get_template('scv_wrap.j2').render(context) save_file(f'{constraint.name}.cpp', self.outdir, c)
def build(self, intfs=Inject('sim/svsock/intfs')): base_addr = os.path.dirname(__file__) env = jinja2.Environment(loader=jinja2.FileSystemLoader(base_addr), trim_blocks=True, lstrip_blocks=True) env.globals.update(zip=zip, int=int, print=print, issubclass=issubclass) context = {'port': self.port} for phase in [ 'declaration', 'init', 'set_data', 'read', 'ack', 'reset', 'sys_reset' ]: context[phase] = {} for i, intf in enumerate(intfs): if not hasattr(intf, phase): continue phase_sv = getattr(intf, phase)() if phase_sv is not None: context[phase][i] = phase_sv res = env.get_template('svsock_top.j2').render(context) save_file('_top.sv', self.outdir, res)
def generate(top, outdir, lang, util, timing, prjdir, part, yosys_preproc=True): if lang not in ['sv', 'v']: raise Exception(f"Synth test unknown language: {lang}") if lang == 'sv': yosys_preproc = False hdlgen(top=top, lang=lang, toplang=lang, outdir=outdir) vgen_map = reg['hdlgen/map'] top_name = vgen_map[top].wrap_module_name if not yosys_preproc or not shutil.which('yosys'): files = list_hdl_files(top, outdir, lang, wrapper=True) if lang == 'sv': save_file(f'{top_name}_synth_wrap.sv', outdir, vgen_map[top].get_synth_wrap(reg[f'svgen/templenv'])) top_name = f'{top_name}_synth_wrap' files.append(os.path.join(outdir, f'{top_name}.sv')) else: files = [os.path.join(outdir, 'synth.v')] # files.append(os.path.join(os.path.dirname(__file__), 'yosys_blocks.v')) yosys_synth(outdir=outdir, srcdir=outdir, top=top, synthout=files[0], synthcmd='synth -noalumacc -noabc -run coarse') jinja_context = { 'res_dir': prjdir, 'outdir': outdir, 'files': files, 'top': top_name, 'util': util, 'timing': timing, 'part': part } env = jinja2.Environment(loader=jinja2.FileSystemLoader( searchpath=os.path.dirname(__file__))) if timing: with open(f'{outdir}/synth.xdc', 'w') as f: f.write( f'create_clock -name clk -period {timing} [get_ports clk]\n') env.get_template('synth.j2').stream(jinja_context).dump( f'{outdir}/synth.tcl')
def generate(self, template_env, outdir): if not self.memoized: self.resolver.generate(template_env, outdir) if not self.node.parent: return # TODO: What about reusing memoized module that didn't need a # wrapper. Discern this. if self.wrapped: save_file(self.wrap_file_name, outdir, self.get_wrap(self.parent_lang))
def drvgen(top, intfdef, outdir): xparams = [] for name, usr_axip in intfdef.items(): if usr_axip.t == 'axidma': xparams.append(f'"C_{name.upper()}_CTRL_BASEADDR"') elif usr_axip.t == 'axi': xparams.append(f'"C_{name.upper()}_BASEADDR"') modinst = reg['hdlgen/map'][top] drvname = modinst.module_name files_dir = os.path.join(os.path.dirname(__file__), '..', 'drivers') env = TemplateEnv(files_dir) context = {'module_name': drvname, 'params': ' '.join(xparams)} files = [] outdir = os.path.join(outdir, f'{drvname}_v1_0') datadir = os.path.join(outdir, 'data') srcdir = os.path.join(outdir, 'src') os.makedirs(datadir, exist_ok=True) os.makedirs(srcdir, exist_ok=True) files.append( save_file(f'{drvname}.mdd', datadir, env.render('.', 'drvgen_mdd.j2', context))) files.append( save_file(f'{drvname}.tcl', datadir, env.render('.', 'drvgen_tcl.j2', context))) context = {'module_name': drvname, 'intfdef': intfdef} files.append( save_file(f'{drvname}.h', srcdir, env.render('.', 'drvgen_new_h.j2', context))) files.append( save_file(f'{drvname}.c', srcdir, env.render('.', 'drvgen_new_c.j2', context))) files.append( copy_file('Makefile', srcdir, os.path.join(files_dir, 'Makefile'))) files.append( copy_file('pgaxi.c', srcdir, os.path.join(files_dir, 'pgaxi.c'))) files.append( copy_file('pgaxi.h', srcdir, os.path.join(files_dir, 'pgaxi.h'))) return files
def generate(self, template_env, outdir): ctx = self.module_context(template_env) module = template_env.render_local(self.impl_path, self.impl_basename, self.module_context(template_env)) if template_env.lang == 'v': index = {} for intf in ctx['intfs']: index[intf['name']] = Intf(intf['type']) index[f'{intf["name"]}_s'] = intf['type'] module = rewrite(module, index) save_file(self.file_basename, outdir, module)
def vgen_generate(top, conf): if not conf['generate']: return top v = VGenGenerateVisitor(top, conf.get('wrapper', False)) for file_names, contents in v.visit(top): if contents: if isinstance(contents, (tuple, list)): for fn, c in zip(file_names, contents): save_file(fn, conf['outdir'], c) else: save_file(file_names, conf['outdir'], contents) return top
def generate(self, template_env, outdir): attrib = self.cfg.get('attrib', None) if isinstance(attrib, str): attrib = [attrib] contents, subsvmods = compile_gear(self.node, template_env, self.module_name, outdir, attrib=attrib) save_file(self.file_basename, outdir, contents) for s in subsvmods: self._files.extend(s.files)
def gen_file(template_fn, out_fn, outdir, context, overwrite=True): template_dir = importlib.machinery.PathFinder().find_spec("pygears_uvm") template_dir = template_dir.submodule_search_locations[0] template_dir = os.path.join(template_dir, "templates") env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir), trim_blocks=True, lstrip_blocks=True) res = env.get_template(template_fn).render(context) if overwrite: save_file(out_fn, outdir, res) else: save_if_nexist(out_fn, outdir, res)
def generate(self, template_env, outdir): ctx = self.module_context(template_env) module = template_env.render_local(self.impl_path, self.impl_basename, self.module_context(template_env)) if template_env.lang == 'v': index = {} for intf in ctx['intfs']: from pygears.hls import ir direction = ir.IntfType.iin if intf['modport'] == 'consumer' else ir.IntfType.iout index[intf['name']] = ir.IntfType[intf['type'], direction] index[f'{intf["name"]}_s'] = intf['type'] module = rewrite(module, index) save_file(self.file_basename, outdir, module)
def create_svrand_top(self): base_addr = os.path.dirname(__file__) env = jinja2.Environment(loader=jinja2.FileSystemLoader(base_addr), trim_blocks=True, lstrip_blocks=True) context = { 'tcons': self.constraints, } res = env.get_template('svrand_top.j2').render(context) save_file('svrand_top.sv', self.outdir, res) # custom classes for con in self.constraints: if con.cls == 'qenvelope': context = {'tcon': con} res = env.get_template('qenvelope.j2').render(context) save_file(f'qenvelope_{con.name}.sv', self.outdir, res)
def xsim(outdir=None, makefile=True, files=None, includes=None, batch=True, seed=None): outdir = os.path.abspath(outdir) if not makefile and not shutil.which('xsim'): raise CosimulatorUnavailable dpi_path = os.path.abspath(os.path.join(ROOT_DIR, 'sim', 'dpi')) context = { 'dti_verif_path': dpi_path, 'outdir': outdir, 'top_name': '_top', 'files': files, 'includes': includes, } base_addr = os.path.dirname(__file__) env = jinja2.Environment(loader=jinja2.FileSystemLoader(base_addr), trim_blocks=True, lstrip_blocks=True) res = env.get_template('run_xsim.j2').render(context) fname = save_file('run_xsim.sh', outdir, res) os.chmod(fname, 0o777) kwds = { 'batch': batch, 'seed': seed if seed is not None else reg["sim/rand_seed"] } if makefile: log.info(f"Waiting for manual XSim invocation. Run script: {fname}...") return None args = ' '.join(f'-{k} {v if not isinstance(v, bool) else ""}' for k, v in kwds.items() if not isinstance(v, bool) or v) # stdout = None stdout = DEVNULL log.info(f'Starting XSim...') return Popen([f'./run_xsim.sh'] + args.split(' '), stdout=stdout, stderr=stdout, cwd=outdir)
def save_if_nexist(fn, outdir, content): file_path = os.path.join(outdir, fn) if os.path.exists(file_path): pass else: save_file(fn, outdir, content)
def ippack(top, dirs, intfdef, lang, prjdir, files, drv_files): hdlgen_map = reg['hdlgen/map'] modinst = hdlgen_map[top] wrap_name = f'wrap_{modinst.module_name}' for fn in files: try: shutil.copy(os.path.join(LIB_VLIB_DIR, fn), dirs['hdl']) except shutil.SameFileError: pass files = [dirs['hdl']] for rtl, mod in hdlgen_map.items(): if isinstance(mod, SVVivModuleInst): for f in mod.files: if os.path.splitext(os.path.basename(f))[0] == mod.wrap_module_name: continue try: os.remove(os.path.join(dirs['hdl'], os.path.basename(f))) except FileNotFoundError: pass xci = glob.glob(f'{mod.resolver.ipdir}/*.xci')[0] if xci not in files: files.append(xci) c_files = [] if drv_files: for f in drv_files: if f[-3:] in ['mdd', 'tcl']: continue if os.path.basename(f) == 'Makefile': continue c_files.append(os.path.relpath(f, dirs['root'])) context = { 'prjdir': prjdir, 'hdldir': dirs['hdl'], 'ipdir': dirs['root'], 'ip_name': top.basename, 'wrap_name': wrap_name, 'files': files, 'drv_files': c_files, 'axi_port_cfg': intfdef, 'description': '"PyGears {} IP"'.format(top.basename) } base_addr = os.path.dirname(__file__) env = jinja2.Environment( extensions=['jinja2.ext.loopcontrols'], loader=jinja2.FileSystemLoader([base_addr, os.path.dirname(base_addr)]), trim_blocks=True, lstrip_blocks=True) env.globals.update(zip=zip) tmplt = 'axipack.j2' env.globals.update(os=os) res = env.get_template(tmplt).render(context) save_file('ippack.tcl', dirs['script'], res)
def build(top, outdir=None, postsynth=False, lang=None, rebuild=True): if isinstance(top, str): top_name = top top = find(top) if top is None: raise Exception(f'No gear found on path: "{top_name}"') if lang is None: lang = reg['hdl/lang'] if lang != 'v': postsynth = False else: pass # postsynth = True file_struct = get_file_struct(top, outdir) outdir = file_struct['outdir'] if not rebuild and os.path.exists(file_struct['dll_path']): return shutil.rmtree(outdir, ignore_errors=True) reg['svgen/spy_connection_template'] = (signal_spy_connect_hide_interm_t if reg['debug/hide_interm_vals'] else signal_spy_connect_t) synth_src_dir = os.path.join(outdir, 'src') hdlgen(top, outdir=synth_src_dir if postsynth else outdir, generate=True, lang=lang, copy_files=True, toplang='v') hdlmod = reg['hdlgen/map'][top] if postsynth: # TODO: change this to the call of the toplevel synth function from pygears.hdl.yosys import synth synth(outdir=outdir, top=top, synthcmd='synth', srcdir=synth_src_dir, synthout=os.path.join(outdir, hdlmod.file_basename)) tracing_enabled = bool(reg['debug/trace']) context = { 'in_ports': top.in_ports, 'out_ports': top.out_ports, 'top_name': hdlmod.wrap_module_name, 'tracing': tracing_enabled, 'aux_clock': reg['sim/aux_clock'] } jenv = jinja2.Environment(trim_blocks=True, lstrip_blocks=True) jenv.globals.update(int=int) jenv.loader = jinja2.FileSystemLoader([os.path.dirname(__file__)]) c = jenv.get_template('sim_veriwrap.j2').render(context) save_file('sim_main.cpp', outdir, c) verilate(outdir, lang, top, hdlmod.wrap_module_name, tracing_enabled) make(file_struct['objdir'], hdlmod.wrap_module_name)
def generate(self, template_env, outdir): save_file(self.file_basename, outdir, self.get_hier_module(template_env))
def generate(top, outdir, lang, intfdef, prjdir, presynth=False, rst=True, drvgen=False): dirs = get_folder_struct(outdir) create_folder_struct(dirs) drv_files = [] if presynth: hdl_lang = 'v' srcdir = os.path.join(dirs['root'], 'src') else: hdl_lang = lang srcdir = dirs['hdl'] top = hdlgen(top, outdir=srcdir, wrapper=False, copy_files=True, lang=hdl_lang, toplang=lang, generate=True) topinst = reg['hdlgen/map'][top] if topinst.wrapped: try: shutil.copy(os.path.join(srcdir, f'{topinst.wrap_module_name}.sv'), dirs['hdl']) except shutil.SameFileError: pass if presynth: if lang == 'sv': # TODO: Use some general file finder (as in hdl resolver) shutil.copy(os.path.join(srcdir, 'dti.sv'), dirs['hdl']) v = IPHierVisitor() v.visit(top) blackbox = [ip.node.name for ip in v.ips] synth('yosys', top=top, outdir=dirs['hdl'], lang=hdl_lang, synthcmd=None, synthout=os.path.join(dirs['hdl'], topinst.file_basename), blackbox=','.join(blackbox), srcdir=srcdir) sigs = [] for s in top.signals.values(): if s.name == 'clk': sigs.append(InSig('aclk', 1)) elif s.name == 'rst': sigs.append(InSig('aresetn', 1)) else: sigs.append(s) if drvgen: drv_files = drvgen(top, intfdef, dirs['driver']) else: drv_files = None wrp, files = generate_wrap(top, intfdef, rst=rst) for p in intfdef.values(): if p.t == 'axi': from pygears.lib.strb_combiner import strb_combiner from pygears import Intf, find from pygears.typing import Tuple, Array, Uint num = p.comp['wdata'].params['wstrb'] # strb_combiner generation requires deeper recursion limit for large buses import sys sys.setrecursionlimit(1500) cur = reg['gear/current_module'] reg['gear/current_module'] = top strb_combiner(Intf(Tuple[Array[Uint[8], num], Uint[num]]), name=f'{p.name}_strb_combiner') reg['gear/current_module'] = cur hdlgen(f'{top.name}/{p.name}_strb_combiner', outdir=srcdir, wrapper=False, copy_files=True, lang=hdl_lang, toplang=lang, generate=True) ippack(top, dirs, intfdef=intfdef, lang=lang, prjdir=prjdir, files=files, drv_files=drv_files) preproc_hdl(dirs['hdl'], mapping=default_preproc) save_file(f'wrap_{os.path.basename(topinst.inst_name)}.{lang}', dirs['hdl'], wrp) # TODO: Remove this when memoization gets smarter. Right now this removes # the problem where memoization can make one IP rely on files stored in # another IP without proper copying reg['hdlgen/map'].clear()
def hdlgen(top=None, lang=None, toplang=None, copy_files=False, generate=True, outdir=None, **conf): if lang is None: lang = reg['hdl/lang'] else: # TODO: should we save/restore previous setting for 'hdl/lang'? reg['hdl/lang'] = lang if outdir is None: outdir = reg['results-dir'] conf['outdir'] = expand(outdir) outdir = conf['outdir'] if isinstance(top, tuple): top = top[0] if isinstance(top, Intf): top = top.producer.gear if top is None: top = reg['gear/root'] elif isinstance(top, str): mtop = find(top) if mtop is None: raise Exception(f'No module "{top}" found') top = mtop else: top = top if toplang is None: toplang = reg['hdl/toplang'] if toplang is None: toplang = reg['hdl/lang'] else: reg['hdl/top'] = top reg['hdl/toplang'] = toplang reg['svgen/conf'] = conf for oper in reg[f'{lang}gen/flow']: oper(top, conf) os.makedirs(outdir, exist_ok=True) if generate: hdlgen_generate(top, conf) hdltop = reg[f'hdlgen/map'][top] if toplang == hdltop.lang == 'sv': save_file(f'{hdltop.wrap_module_name}_wrap.sv', outdir, hdltop.get_synth_wrap(reg[f'svgen/templenv'])) for (modname, lang), (fn, fn_dis) in reg['hdlgen/disambig'].items(): with open(fn) as fin: with open(fn_dis, 'w') as fout: mod = fin.read() mod = mod.replace(f'module {modname}', f'module {modname}_{lang}') fout.write(mod) if copy_files and generate: for fn in list_hdl_files(top.name, outdir=outdir, rtl_only=True): modname, ext = os.path.splitext(os.path.basename(fn)) if (modname, ext[1:]) in reg['hdlgen/disambig']: continue try: shutil.copy(fn, outdir) except shutil.SameFileError: pass except FileNotFoundError: pass return top