1*9341e7e3Sxiaofeibao-xjtu#! /usr/bin/env python3 2*9341e7e3Sxiaofeibao-xjtu 3*9341e7e3Sxiaofeibao-xjtuimport argparse 4*9341e7e3Sxiaofeibao-xjtuimport os 5*9341e7e3Sxiaofeibao-xjtuimport re 6*9341e7e3Sxiaofeibao-xjtufrom datetime import date 7*9341e7e3Sxiaofeibao-xjtufrom shutil import copy, copytree 8*9341e7e3Sxiaofeibao-xjtu 9*9341e7e3Sxiaofeibao-xjtuimport xlsxwriter 10*9341e7e3Sxiaofeibao-xjtu 11*9341e7e3Sxiaofeibao-xjtu 12*9341e7e3Sxiaofeibao-xjtuclass VIO(object): 13*9341e7e3Sxiaofeibao-xjtu def __init__(self, info): 14*9341e7e3Sxiaofeibao-xjtu self.info = info 15*9341e7e3Sxiaofeibao-xjtu assert(self.info[0] in ["input", "output"]) 16*9341e7e3Sxiaofeibao-xjtu self.direction = self.info[0] 17*9341e7e3Sxiaofeibao-xjtu self.width = 0 if self.info[1] == "" else int(self.info[1].split(":")[0].replace("[", "")) 18*9341e7e3Sxiaofeibao-xjtu self.width += 1 19*9341e7e3Sxiaofeibao-xjtu self.name = self.info[2] 20*9341e7e3Sxiaofeibao-xjtu 21*9341e7e3Sxiaofeibao-xjtu def get_direction(self): 22*9341e7e3Sxiaofeibao-xjtu return self.direction 23*9341e7e3Sxiaofeibao-xjtu 24*9341e7e3Sxiaofeibao-xjtu def get_width(self): 25*9341e7e3Sxiaofeibao-xjtu return self.width 26*9341e7e3Sxiaofeibao-xjtu 27*9341e7e3Sxiaofeibao-xjtu def get_name(self): 28*9341e7e3Sxiaofeibao-xjtu return self.name 29*9341e7e3Sxiaofeibao-xjtu 30*9341e7e3Sxiaofeibao-xjtu def startswith(self, prefix): 31*9341e7e3Sxiaofeibao-xjtu return self.info[2].startswith(prefix) 32*9341e7e3Sxiaofeibao-xjtu 33*9341e7e3Sxiaofeibao-xjtu def __str__(self): 34*9341e7e3Sxiaofeibao-xjtu return " ".join(self.info) 35*9341e7e3Sxiaofeibao-xjtu 36*9341e7e3Sxiaofeibao-xjtu def __repr__(self): 37*9341e7e3Sxiaofeibao-xjtu return self.__str__() 38*9341e7e3Sxiaofeibao-xjtu 39*9341e7e3Sxiaofeibao-xjtu def __lt__(self, other): 40*9341e7e3Sxiaofeibao-xjtu return str(self) < str(other) 41*9341e7e3Sxiaofeibao-xjtu 42*9341e7e3Sxiaofeibao-xjtuclass VModule(object): 43*9341e7e3Sxiaofeibao-xjtu module_re = re.compile(r'^\s*module\s*(\w+)\s*(#\(?|)\s*(\(.*|)\s*$') 44*9341e7e3Sxiaofeibao-xjtu io_re = re.compile(r'^\s*(input|output)\s*(\[\s*\d+\s*:\s*\d+\s*\]|)\s*(\w+),?\s*$') 45*9341e7e3Sxiaofeibao-xjtu submodule_re = re.compile(r'^\s*(\w+)\s*(#\(.*\)|)\s*(\w+)\s*\(\s*(|//.*)\s*$') 46*9341e7e3Sxiaofeibao-xjtu difftest_module_re = re.compile(r'^ \w*Difftest\w+\s+\w+ \( //.*$') 47*9341e7e3Sxiaofeibao-xjtu 48*9341e7e3Sxiaofeibao-xjtu def __init__(self, name): 49*9341e7e3Sxiaofeibao-xjtu self.name = name 50*9341e7e3Sxiaofeibao-xjtu self.lines = [] 51*9341e7e3Sxiaofeibao-xjtu self.io = [] 52*9341e7e3Sxiaofeibao-xjtu self.submodule = dict() 53*9341e7e3Sxiaofeibao-xjtu self.instance = set() 54*9341e7e3Sxiaofeibao-xjtu self.in_difftest = False 55*9341e7e3Sxiaofeibao-xjtu 56*9341e7e3Sxiaofeibao-xjtu def add_line(self, line): 57*9341e7e3Sxiaofeibao-xjtu debug_dontCare = False 58*9341e7e3Sxiaofeibao-xjtu if "RegFile" in self.name and "@(posedge clock)" in line: 59*9341e7e3Sxiaofeibao-xjtu line = line.replace("posedge", "negedge") 60*9341e7e3Sxiaofeibao-xjtu elif "RenameTable" in self.name: 61*9341e7e3Sxiaofeibao-xjtu if line.strip().startswith("assign io_debug_rdata_"): 62*9341e7e3Sxiaofeibao-xjtu debug_dontCare = True 63*9341e7e3Sxiaofeibao-xjtu elif "SynRegfileSlice" in self.name: 64*9341e7e3Sxiaofeibao-xjtu if line.strip().startswith("assign io_debug_ports_"): 65*9341e7e3Sxiaofeibao-xjtu debug_dontCare = True 66*9341e7e3Sxiaofeibao-xjtu 67*9341e7e3Sxiaofeibao-xjtu # start of difftest module 68*9341e7e3Sxiaofeibao-xjtu difftest_match = self.difftest_module_re.match(line) 69*9341e7e3Sxiaofeibao-xjtu if difftest_match: 70*9341e7e3Sxiaofeibao-xjtu self.in_difftest = True 71*9341e7e3Sxiaofeibao-xjtu self.lines.append("`ifndef SYNTHESIS\n") 72*9341e7e3Sxiaofeibao-xjtu 73*9341e7e3Sxiaofeibao-xjtu if debug_dontCare: 74*9341e7e3Sxiaofeibao-xjtu self.lines.append("`ifndef SYNTHESIS\n") 75*9341e7e3Sxiaofeibao-xjtu self.lines.append(line) 76*9341e7e3Sxiaofeibao-xjtu if debug_dontCare: 77*9341e7e3Sxiaofeibao-xjtu self.lines.append("`else\n") 78*9341e7e3Sxiaofeibao-xjtu debug_dontCare_name = line.strip().split(" ")[1] 79*9341e7e3Sxiaofeibao-xjtu self.lines.append(f" assign {debug_dontCare_name} = 0;\n") 80*9341e7e3Sxiaofeibao-xjtu self.lines.append("`endif\n") 81*9341e7e3Sxiaofeibao-xjtu 82*9341e7e3Sxiaofeibao-xjtu # end of difftest module 83*9341e7e3Sxiaofeibao-xjtu if self.in_difftest and line.strip() == ");": 84*9341e7e3Sxiaofeibao-xjtu self.in_difftest = False 85*9341e7e3Sxiaofeibao-xjtu self.lines.append("`endif\n") 86*9341e7e3Sxiaofeibao-xjtu 87*9341e7e3Sxiaofeibao-xjtu if len(self.lines): 88*9341e7e3Sxiaofeibao-xjtu io_match = self.io_re.match(line) 89*9341e7e3Sxiaofeibao-xjtu if io_match: 90*9341e7e3Sxiaofeibao-xjtu this_io = VIO(tuple(map(lambda i: io_match.group(i), range(1, 4)))) 91*9341e7e3Sxiaofeibao-xjtu self.io.append(this_io) 92*9341e7e3Sxiaofeibao-xjtu submodule_match = self.submodule_re.match(line) 93*9341e7e3Sxiaofeibao-xjtu if submodule_match: 94*9341e7e3Sxiaofeibao-xjtu this_submodule = submodule_match.group(1) 95*9341e7e3Sxiaofeibao-xjtu if this_submodule != "module": 96*9341e7e3Sxiaofeibao-xjtu self.add_submodule(this_submodule) 97*9341e7e3Sxiaofeibao-xjtu self.add_instance(this_submodule, submodule_match.group(3)) 98*9341e7e3Sxiaofeibao-xjtu 99*9341e7e3Sxiaofeibao-xjtu def add_lines(self, lines): 100*9341e7e3Sxiaofeibao-xjtu for line in lines: 101*9341e7e3Sxiaofeibao-xjtu self.add_line(line) 102*9341e7e3Sxiaofeibao-xjtu 103*9341e7e3Sxiaofeibao-xjtu def get_name(self): 104*9341e7e3Sxiaofeibao-xjtu return self.name 105*9341e7e3Sxiaofeibao-xjtu 106*9341e7e3Sxiaofeibao-xjtu def set_name(self, updated_name): 107*9341e7e3Sxiaofeibao-xjtu for i, line in enumerate(self.lines): 108*9341e7e3Sxiaofeibao-xjtu module_match = VModule.module_re.match(line) 109*9341e7e3Sxiaofeibao-xjtu if module_match: 110*9341e7e3Sxiaofeibao-xjtu print(f"Line Previously: {line.strip()}") 111*9341e7e3Sxiaofeibao-xjtu updated_line = line.replace(self.name, updated_name) 112*9341e7e3Sxiaofeibao-xjtu print(f"Line Updated: {updated_line.strip()}") 113*9341e7e3Sxiaofeibao-xjtu self.lines[i] = updated_line 114*9341e7e3Sxiaofeibao-xjtu break 115*9341e7e3Sxiaofeibao-xjtu self.name = updated_name 116*9341e7e3Sxiaofeibao-xjtu 117*9341e7e3Sxiaofeibao-xjtu def get_lines(self): 118*9341e7e3Sxiaofeibao-xjtu return self.lines + ["\n"] 119*9341e7e3Sxiaofeibao-xjtu 120*9341e7e3Sxiaofeibao-xjtu def get_io(self, prefix="", match=""): 121*9341e7e3Sxiaofeibao-xjtu if match: 122*9341e7e3Sxiaofeibao-xjtu r = re.compile(match) 123*9341e7e3Sxiaofeibao-xjtu return list(filter(lambda x: r.match(str(x)), self.io)) 124*9341e7e3Sxiaofeibao-xjtu else: 125*9341e7e3Sxiaofeibao-xjtu return list(filter(lambda x: x.startswith(prefix), self.io)) 126*9341e7e3Sxiaofeibao-xjtu 127*9341e7e3Sxiaofeibao-xjtu def get_submodule(self): 128*9341e7e3Sxiaofeibao-xjtu return self.submodule 129*9341e7e3Sxiaofeibao-xjtu 130*9341e7e3Sxiaofeibao-xjtu def get_instance(self): 131*9341e7e3Sxiaofeibao-xjtu return self.instance 132*9341e7e3Sxiaofeibao-xjtu 133*9341e7e3Sxiaofeibao-xjtu def add_submodule(self, name): 134*9341e7e3Sxiaofeibao-xjtu self.submodule[name] = self.submodule.get(name, 0) + 1 135*9341e7e3Sxiaofeibao-xjtu 136*9341e7e3Sxiaofeibao-xjtu def add_instance(self, name, instance_name): 137*9341e7e3Sxiaofeibao-xjtu self.instance.add((name, instance_name)) 138*9341e7e3Sxiaofeibao-xjtu 139*9341e7e3Sxiaofeibao-xjtu def add_submodules(self, names): 140*9341e7e3Sxiaofeibao-xjtu for name in names: 141*9341e7e3Sxiaofeibao-xjtu self.add_submodule(name) 142*9341e7e3Sxiaofeibao-xjtu 143*9341e7e3Sxiaofeibao-xjtu def dump_io(self, prefix="", match=""): 144*9341e7e3Sxiaofeibao-xjtu print("\n".join(map(lambda x: str(x), self.get_io(prefix, match)))) 145*9341e7e3Sxiaofeibao-xjtu 146*9341e7e3Sxiaofeibao-xjtu def get_mbist_type(self): 147*9341e7e3Sxiaofeibao-xjtu r = re.compile(r'input.*mbist_(\w+)_(trim|sleep)_fuse.*') 148*9341e7e3Sxiaofeibao-xjtu mbist_fuse_io = list(filter(lambda x: r.match(str(x)), self.io)) 149*9341e7e3Sxiaofeibao-xjtu mbist_types = list(set(map(lambda io: io.get_name().split("_")[1], mbist_fuse_io))) 150*9341e7e3Sxiaofeibao-xjtu assert(len(mbist_types) == 1) 151*9341e7e3Sxiaofeibao-xjtu return mbist_types[0] 152*9341e7e3Sxiaofeibao-xjtu 153*9341e7e3Sxiaofeibao-xjtu def replace(self, s): 154*9341e7e3Sxiaofeibao-xjtu self.lines = [s] 155*9341e7e3Sxiaofeibao-xjtu 156*9341e7e3Sxiaofeibao-xjtu def replace_with_macro(self, macro, s): 157*9341e7e3Sxiaofeibao-xjtu replaced_lines = [] 158*9341e7e3Sxiaofeibao-xjtu in_io, in_body = False, False 159*9341e7e3Sxiaofeibao-xjtu for line in self.lines: 160*9341e7e3Sxiaofeibao-xjtu if self.io_re.match(line): 161*9341e7e3Sxiaofeibao-xjtu in_io = True 162*9341e7e3Sxiaofeibao-xjtu replaced_lines.append(line) 163*9341e7e3Sxiaofeibao-xjtu elif in_io: 164*9341e7e3Sxiaofeibao-xjtu in_io = False 165*9341e7e3Sxiaofeibao-xjtu in_body = True 166*9341e7e3Sxiaofeibao-xjtu replaced_lines.append(line) # This is ");" 167*9341e7e3Sxiaofeibao-xjtu replaced_lines.append(f"`ifdef {macro}\n") 168*9341e7e3Sxiaofeibao-xjtu replaced_lines.append(s) 169*9341e7e3Sxiaofeibao-xjtu replaced_lines.append(f"`else\n") 170*9341e7e3Sxiaofeibao-xjtu elif in_body: 171*9341e7e3Sxiaofeibao-xjtu if line.strip() == "endmodule": 172*9341e7e3Sxiaofeibao-xjtu replaced_lines.append(f"`endif // {macro}\n") 173*9341e7e3Sxiaofeibao-xjtu replaced_lines.append(line) 174*9341e7e3Sxiaofeibao-xjtu else: 175*9341e7e3Sxiaofeibao-xjtu replaced_lines.append(line) 176*9341e7e3Sxiaofeibao-xjtu self.lines = replaced_lines 177*9341e7e3Sxiaofeibao-xjtu 178*9341e7e3Sxiaofeibao-xjtu def __str__(self): 179*9341e7e3Sxiaofeibao-xjtu module_name = "Module {}: \n".format(self.name) 180*9341e7e3Sxiaofeibao-xjtu module_io = "\n".join(map(lambda x: "\t" + str(x), self.io)) + "\n" 181*9341e7e3Sxiaofeibao-xjtu return module_name + module_io 182*9341e7e3Sxiaofeibao-xjtu 183*9341e7e3Sxiaofeibao-xjtu def __repr__(self): 184*9341e7e3Sxiaofeibao-xjtu return "{}".format(self.name) 185*9341e7e3Sxiaofeibao-xjtu 186*9341e7e3Sxiaofeibao-xjtu 187*9341e7e3Sxiaofeibao-xjtuclass VCollection(object): 188*9341e7e3Sxiaofeibao-xjtu def __init__(self): 189*9341e7e3Sxiaofeibao-xjtu self.modules = [] 190*9341e7e3Sxiaofeibao-xjtu self.ancestors = [] 191*9341e7e3Sxiaofeibao-xjtu 192*9341e7e3Sxiaofeibao-xjtu def load_modules(self, vfile): 193*9341e7e3Sxiaofeibao-xjtu in_module = False 194*9341e7e3Sxiaofeibao-xjtu current_module = None 195*9341e7e3Sxiaofeibao-xjtu skipped_lines = [] 196*9341e7e3Sxiaofeibao-xjtu with open(vfile) as f: 197*9341e7e3Sxiaofeibao-xjtu print("Loading modules from {}...".format(vfile)) 198*9341e7e3Sxiaofeibao-xjtu for i, line in enumerate(f): 199*9341e7e3Sxiaofeibao-xjtu module_match = VModule.module_re.match(line) 200*9341e7e3Sxiaofeibao-xjtu if module_match: 201*9341e7e3Sxiaofeibao-xjtu module_name = module_match.group(1) 202*9341e7e3Sxiaofeibao-xjtu if in_module or current_module is not None: 203*9341e7e3Sxiaofeibao-xjtu print("Line {}: does not find endmodule for {}".format(i, current_module)) 204*9341e7e3Sxiaofeibao-xjtu exit() 205*9341e7e3Sxiaofeibao-xjtu current_module = VModule(module_name) 206*9341e7e3Sxiaofeibao-xjtu for skip_line in skipped_lines: 207*9341e7e3Sxiaofeibao-xjtu print("[WARNING]{}:{} is added to module {}:\n{}".format(vfile, i, module_name, skip_line), end="") 208*9341e7e3Sxiaofeibao-xjtu current_module.add_line(skip_line) 209*9341e7e3Sxiaofeibao-xjtu skipped_lines = [] 210*9341e7e3Sxiaofeibao-xjtu in_module = True 211*9341e7e3Sxiaofeibao-xjtu if not in_module or current_module is None: 212*9341e7e3Sxiaofeibao-xjtu if line.strip() != "":# and not line.strip().startswith("//"): 213*9341e7e3Sxiaofeibao-xjtu skipped_lines.append(line) 214*9341e7e3Sxiaofeibao-xjtu continue 215*9341e7e3Sxiaofeibao-xjtu current_module.add_line(line) 216*9341e7e3Sxiaofeibao-xjtu if line.startswith("endmodule"): 217*9341e7e3Sxiaofeibao-xjtu self.modules.append(current_module) 218*9341e7e3Sxiaofeibao-xjtu current_module = None 219*9341e7e3Sxiaofeibao-xjtu in_module = False 220*9341e7e3Sxiaofeibao-xjtu 221*9341e7e3Sxiaofeibao-xjtu def get_module_names(self): 222*9341e7e3Sxiaofeibao-xjtu return list(map(lambda m: m.get_name(), self.modules)) 223*9341e7e3Sxiaofeibao-xjtu 224*9341e7e3Sxiaofeibao-xjtu def get_all_modules(self, match=""): 225*9341e7e3Sxiaofeibao-xjtu if match: 226*9341e7e3Sxiaofeibao-xjtu r = re.compile(match) 227*9341e7e3Sxiaofeibao-xjtu return list(filter(lambda m: r.match(m.get_name()), self.modules)) 228*9341e7e3Sxiaofeibao-xjtu else: 229*9341e7e3Sxiaofeibao-xjtu return self.modules 230*9341e7e3Sxiaofeibao-xjtu 231*9341e7e3Sxiaofeibao-xjtu def get_module(self, name, negedge_modules=None, negedge_prefix=None, with_submodule=False, try_prefix=None, ignore_modules=None): 232*9341e7e3Sxiaofeibao-xjtu if negedge_modules is None: 233*9341e7e3Sxiaofeibao-xjtu negedge_modules = [] 234*9341e7e3Sxiaofeibao-xjtu target = None 235*9341e7e3Sxiaofeibao-xjtu for module in self.modules: 236*9341e7e3Sxiaofeibao-xjtu if module.get_name() == name: 237*9341e7e3Sxiaofeibao-xjtu target = module 238*9341e7e3Sxiaofeibao-xjtu if target is None and try_prefix is not None: 239*9341e7e3Sxiaofeibao-xjtu for module in self.modules: 240*9341e7e3Sxiaofeibao-xjtu name_no_prefix = name[len(try_prefix):] 241*9341e7e3Sxiaofeibao-xjtu if module.get_name() == name_no_prefix: 242*9341e7e3Sxiaofeibao-xjtu target = module 243*9341e7e3Sxiaofeibao-xjtu print(f"Replace {name_no_prefix} with modulename {name}. Please DOUBLE CHECK the verilog.") 244*9341e7e3Sxiaofeibao-xjtu target.set_name(name) 245*9341e7e3Sxiaofeibao-xjtu if target is None or not with_submodule: 246*9341e7e3Sxiaofeibao-xjtu return target 247*9341e7e3Sxiaofeibao-xjtu submodules = set() 248*9341e7e3Sxiaofeibao-xjtu submodules.add(target) 249*9341e7e3Sxiaofeibao-xjtu for submodule, instance in target.get_instance(): 250*9341e7e3Sxiaofeibao-xjtu if ignore_modules is not None and submodule in ignore_modules: 251*9341e7e3Sxiaofeibao-xjtu continue 252*9341e7e3Sxiaofeibao-xjtu self.ancestors.append(instance) 253*9341e7e3Sxiaofeibao-xjtu is_negedge_module = False 254*9341e7e3Sxiaofeibao-xjtu if negedge_prefix is not None: 255*9341e7e3Sxiaofeibao-xjtu if submodule.startswith(negedge_prefix): 256*9341e7e3Sxiaofeibao-xjtu is_negedge_module = True 257*9341e7e3Sxiaofeibao-xjtu elif try_prefix is not None and submodule.startswith(try_prefix + negedge_prefix): 258*9341e7e3Sxiaofeibao-xjtu is_negedge_module = True 259*9341e7e3Sxiaofeibao-xjtu if is_negedge_module: 260*9341e7e3Sxiaofeibao-xjtu negedge_modules.append("/".join(self.ancestors)) 261*9341e7e3Sxiaofeibao-xjtu result = self.get_module(submodule, negedge_modules, negedge_prefix, with_submodule=True, try_prefix=try_prefix, ignore_modules=ignore_modules) 262*9341e7e3Sxiaofeibao-xjtu self.ancestors.pop() 263*9341e7e3Sxiaofeibao-xjtu if result is None: 264*9341e7e3Sxiaofeibao-xjtu print("Error: cannot find submodules of {} or the module itself".format(submodule)) 265*9341e7e3Sxiaofeibao-xjtu return None 266*9341e7e3Sxiaofeibao-xjtu submodules.update(result) 267*9341e7e3Sxiaofeibao-xjtu return submodules 268*9341e7e3Sxiaofeibao-xjtu 269*9341e7e3Sxiaofeibao-xjtu def dump_to_file(self, name, output_dir, with_submodule=True, split=True, try_prefix=None, ignore_modules=None): 270*9341e7e3Sxiaofeibao-xjtu print("Dump module {} to {}...".format(name, output_dir)) 271*9341e7e3Sxiaofeibao-xjtu modules = self.get_module(name, with_submodule=with_submodule, try_prefix=try_prefix, ignore_modules=ignore_modules) 272*9341e7e3Sxiaofeibao-xjtu if modules is None: 273*9341e7e3Sxiaofeibao-xjtu print("does not find module", name) 274*9341e7e3Sxiaofeibao-xjtu return False 275*9341e7e3Sxiaofeibao-xjtu # print("All modules:", modules) 276*9341e7e3Sxiaofeibao-xjtu if not with_submodule: 277*9341e7e3Sxiaofeibao-xjtu modules = [modules] 278*9341e7e3Sxiaofeibao-xjtu if not os.path.isdir(output_dir): 279*9341e7e3Sxiaofeibao-xjtu os.makedirs(output_dir, exist_ok=True) 280*9341e7e3Sxiaofeibao-xjtu if split: 281*9341e7e3Sxiaofeibao-xjtu for module in modules: 282*9341e7e3Sxiaofeibao-xjtu output_file = os.path.join(output_dir, module.get_name() + ".v") 283*9341e7e3Sxiaofeibao-xjtu # print("write module", module.get_name(), "to", output_file) 284*9341e7e3Sxiaofeibao-xjtu with open(output_file, "w") as f: 285*9341e7e3Sxiaofeibao-xjtu f.writelines(module.get_lines()) 286*9341e7e3Sxiaofeibao-xjtu else: 287*9341e7e3Sxiaofeibao-xjtu output_file = os.path.join(output_dir, name + ".v") 288*9341e7e3Sxiaofeibao-xjtu with open(output_file, "w") as f: 289*9341e7e3Sxiaofeibao-xjtu for module in modules: 290*9341e7e3Sxiaofeibao-xjtu f.writelines(module.get_lines()) 291*9341e7e3Sxiaofeibao-xjtu return True 292*9341e7e3Sxiaofeibao-xjtu 293*9341e7e3Sxiaofeibao-xjtu def dump_negedge_modules_to_file(self, name, output_dir, with_submodule=True, try_prefix=None): 294*9341e7e3Sxiaofeibao-xjtu print("Dump negedge module {} to {}...".format(name, output_dir)) 295*9341e7e3Sxiaofeibao-xjtu negedge_modules = [] 296*9341e7e3Sxiaofeibao-xjtu self.get_module(name, negedge_modules, "NegedgeDataModule_", with_submodule=with_submodule, try_prefix=try_prefix) 297*9341e7e3Sxiaofeibao-xjtu negedge_modules_sort = [] 298*9341e7e3Sxiaofeibao-xjtu for negedge in negedge_modules: 299*9341e7e3Sxiaofeibao-xjtu re_degits = re.compile(r".*[0-9]$") 300*9341e7e3Sxiaofeibao-xjtu if re_degits.match(negedge): 301*9341e7e3Sxiaofeibao-xjtu negedge_module, num = negedge.rsplit("_", 1) 302*9341e7e3Sxiaofeibao-xjtu else: 303*9341e7e3Sxiaofeibao-xjtu negedge_module, num = negedge, -1 304*9341e7e3Sxiaofeibao-xjtu negedge_modules_sort.append((negedge_module, int(num))) 305*9341e7e3Sxiaofeibao-xjtu negedge_modules_sort.sort(key = lambda x : (x[0], x[1])) 306*9341e7e3Sxiaofeibao-xjtu output_file = os.path.join(output_dir, "negedge_modules.txt") 307*9341e7e3Sxiaofeibao-xjtu with open(output_file, "w")as f: 308*9341e7e3Sxiaofeibao-xjtu f.write("set sregfile_list [list\n") 309*9341e7e3Sxiaofeibao-xjtu for negedge_module, num in negedge_modules_sort: 310*9341e7e3Sxiaofeibao-xjtu if num == -1: 311*9341e7e3Sxiaofeibao-xjtu f.write("{}\n".format(negedge_module)) 312*9341e7e3Sxiaofeibao-xjtu else: 313*9341e7e3Sxiaofeibao-xjtu f.write("{}_{}\n".format(negedge_module, num)) 314*9341e7e3Sxiaofeibao-xjtu f.write("]") 315*9341e7e3Sxiaofeibao-xjtu 316*9341e7e3Sxiaofeibao-xjtu def add_module(self, name, line): 317*9341e7e3Sxiaofeibao-xjtu module = VModule(name) 318*9341e7e3Sxiaofeibao-xjtu module.add_line(line) 319*9341e7e3Sxiaofeibao-xjtu self.modules.append(module) 320*9341e7e3Sxiaofeibao-xjtu return module 321*9341e7e3Sxiaofeibao-xjtu 322*9341e7e3Sxiaofeibao-xjtu def count_instances(self, top_name, name): 323*9341e7e3Sxiaofeibao-xjtu if top_name == name: 324*9341e7e3Sxiaofeibao-xjtu return 1 325*9341e7e3Sxiaofeibao-xjtu count = 0 326*9341e7e3Sxiaofeibao-xjtu top_module = self.get_module(top_name) 327*9341e7e3Sxiaofeibao-xjtu if top_module is not None: 328*9341e7e3Sxiaofeibao-xjtu for submodule in top_module.submodule: 329*9341e7e3Sxiaofeibao-xjtu count += top_module.submodule[submodule] * self.count_instances(submodule, name) 330*9341e7e3Sxiaofeibao-xjtu return count 331*9341e7e3Sxiaofeibao-xjtu 332*9341e7e3Sxiaofeibao-xjtudef check_data_module_template(collection): 333*9341e7e3Sxiaofeibao-xjtu error_modules = [] 334*9341e7e3Sxiaofeibao-xjtu field_re = re.compile(r'io_(w|r)data_(\d*)(_.*|)') 335*9341e7e3Sxiaofeibao-xjtu modules = collection.get_all_modules(match="(Sync|Async)DataModuleTemplate.*") 336*9341e7e3Sxiaofeibao-xjtu for module in modules: 337*9341e7e3Sxiaofeibao-xjtu module_name = module.get_name() 338*9341e7e3Sxiaofeibao-xjtu print("Checking", module_name, "...") 339*9341e7e3Sxiaofeibao-xjtu wdata_all = sorted(module.get_io(match="input.*wdata.*")) 340*9341e7e3Sxiaofeibao-xjtu rdata_all = sorted(module.get_io(match="output.*rdata.*")) 341*9341e7e3Sxiaofeibao-xjtu wdata_pattern = set(map(lambda x: " ".join((str(x.get_width()), field_re.match(x.get_name()).group(3))), wdata_all)) 342*9341e7e3Sxiaofeibao-xjtu rdata_pattern = set(map(lambda x: " ".join((str(x.get_width()), field_re.match(x.get_name()).group(3))), rdata_all)) 343*9341e7e3Sxiaofeibao-xjtu if wdata_pattern != rdata_pattern: 344*9341e7e3Sxiaofeibao-xjtu print("Errors:") 345*9341e7e3Sxiaofeibao-xjtu print(" wdata only:", sorted(wdata_pattern - rdata_pattern, key=lambda x: x.split(" ")[1])) 346*9341e7e3Sxiaofeibao-xjtu print(" rdata only:", sorted(rdata_pattern - wdata_pattern, key=lambda x: x.split(" ")[1])) 347*9341e7e3Sxiaofeibao-xjtu print("In", str(module)) 348*9341e7e3Sxiaofeibao-xjtu error_modules.append(module) 349*9341e7e3Sxiaofeibao-xjtu return error_modules 350*9341e7e3Sxiaofeibao-xjtu 351*9341e7e3Sxiaofeibao-xjtudef create_verilog(files, top_module, config, try_prefix=None, ignore_modules=None): 352*9341e7e3Sxiaofeibao-xjtu collection = VCollection() 353*9341e7e3Sxiaofeibao-xjtu for f in files: 354*9341e7e3Sxiaofeibao-xjtu collection.load_modules(f) 355*9341e7e3Sxiaofeibao-xjtu today = date.today() 356*9341e7e3Sxiaofeibao-xjtu directory = f'{top_module}-Release-{config}-{today.strftime("%b-%d-%Y")}' 357*9341e7e3Sxiaofeibao-xjtu success = collection.dump_to_file(top_module, os.path.join(directory, top_module), try_prefix=try_prefix, ignore_modules=ignore_modules) 358*9341e7e3Sxiaofeibao-xjtu collection.dump_negedge_modules_to_file(top_module, directory, try_prefix=try_prefix) 359*9341e7e3Sxiaofeibao-xjtu if not success: 360*9341e7e3Sxiaofeibao-xjtu return None, None 361*9341e7e3Sxiaofeibao-xjtu return collection, os.path.realpath(directory) 362*9341e7e3Sxiaofeibao-xjtu 363*9341e7e3Sxiaofeibao-xjtudef get_files(build_path): 364*9341e7e3Sxiaofeibao-xjtu files = [] 365*9341e7e3Sxiaofeibao-xjtu for f in os.listdir(build_path): 366*9341e7e3Sxiaofeibao-xjtu file_path = os.path.join(build_path, f) 367*9341e7e3Sxiaofeibao-xjtu if f.endswith(".v") or f.endswith(".sv"): 368*9341e7e3Sxiaofeibao-xjtu files.append(file_path) 369*9341e7e3Sxiaofeibao-xjtu elif os.path.isdir(file_path): 370*9341e7e3Sxiaofeibao-xjtu files += get_files(file_path) 371*9341e7e3Sxiaofeibao-xjtu return files 372*9341e7e3Sxiaofeibao-xjtu 373*9341e7e3Sxiaofeibao-xjtudef create_filelist(filelist_name, out_dir, file_dirs=None, extra_lines=[]): 374*9341e7e3Sxiaofeibao-xjtu if file_dirs is None: 375*9341e7e3Sxiaofeibao-xjtu file_dirs = [filelist_name] 376*9341e7e3Sxiaofeibao-xjtu filelist_entries = [] 377*9341e7e3Sxiaofeibao-xjtu for file_dir in file_dirs: 378*9341e7e3Sxiaofeibao-xjtu for filename in os.listdir(os.path.join(out_dir, file_dir)): 379*9341e7e3Sxiaofeibao-xjtu if filename.endswith(".v") or filename.endswith(".sv"): 380*9341e7e3Sxiaofeibao-xjtu # check whether it exists in previous directories 381*9341e7e3Sxiaofeibao-xjtu # this infers an implicit priority between the file_dirs 382*9341e7e3Sxiaofeibao-xjtu has_found = False 383*9341e7e3Sxiaofeibao-xjtu for entry in filelist_entries: 384*9341e7e3Sxiaofeibao-xjtu if entry.endswith(filename): 385*9341e7e3Sxiaofeibao-xjtu has_found = True 386*9341e7e3Sxiaofeibao-xjtu break 387*9341e7e3Sxiaofeibao-xjtu if has_found: 388*9341e7e3Sxiaofeibao-xjtu continue 389*9341e7e3Sxiaofeibao-xjtu filelist_entry = os.path.join(file_dir, filename) 390*9341e7e3Sxiaofeibao-xjtu filelist_entries.append(filelist_entry) 391*9341e7e3Sxiaofeibao-xjtu with open(os.path.join(out_dir, f"{filelist_name}.f"), "w") as f: 392*9341e7e3Sxiaofeibao-xjtu for entry in filelist_entries + extra_lines: 393*9341e7e3Sxiaofeibao-xjtu f.write(f"{entry}\n") 394*9341e7e3Sxiaofeibao-xjtu 395*9341e7e3Sxiaofeibao-xjtu 396*9341e7e3Sxiaofeibao-xjtuclass SRAMConfiguration(object): 397*9341e7e3Sxiaofeibao-xjtu ARRAY_NAME = "sram_array_(\d)p(\d+)x(\d+)m(\d+)(_multicycle|)(_repair|)" 398*9341e7e3Sxiaofeibao-xjtu 399*9341e7e3Sxiaofeibao-xjtu SINGLE_PORT = 0 400*9341e7e3Sxiaofeibao-xjtu SINGLE_PORT_MASK = 1 401*9341e7e3Sxiaofeibao-xjtu DUAL_PORT = 2 402*9341e7e3Sxiaofeibao-xjtu DUAL_PORT_MASK = 3 403*9341e7e3Sxiaofeibao-xjtu 404*9341e7e3Sxiaofeibao-xjtu def __init__(self): 405*9341e7e3Sxiaofeibao-xjtu self.name = None 406*9341e7e3Sxiaofeibao-xjtu self.depth = None 407*9341e7e3Sxiaofeibao-xjtu self.width = None 408*9341e7e3Sxiaofeibao-xjtu self.ports = None 409*9341e7e3Sxiaofeibao-xjtu self.mask_gran = None 410*9341e7e3Sxiaofeibao-xjtu self.has_multi_cycle = False 411*9341e7e3Sxiaofeibao-xjtu self.has_repair = False 412*9341e7e3Sxiaofeibao-xjtu 413*9341e7e3Sxiaofeibao-xjtu def size(self): 414*9341e7e3Sxiaofeibao-xjtu return self.depth * self.width 415*9341e7e3Sxiaofeibao-xjtu 416*9341e7e3Sxiaofeibao-xjtu def is_single_port(self): 417*9341e7e3Sxiaofeibao-xjtu return self.ports == self.SINGLE_PORT or self.ports == self.SINGLE_PORT_MASK 418*9341e7e3Sxiaofeibao-xjtu 419*9341e7e3Sxiaofeibao-xjtu def mask_width(self): 420*9341e7e3Sxiaofeibao-xjtu return self.width // self.mask_gran 421*9341e7e3Sxiaofeibao-xjtu 422*9341e7e3Sxiaofeibao-xjtu def match_module_name(self, module_name): 423*9341e7e3Sxiaofeibao-xjtu sram_array_re = re.compile(self.ARRAY_NAME) 424*9341e7e3Sxiaofeibao-xjtu module_name_match = sram_array_re.match(self.name) 425*9341e7e3Sxiaofeibao-xjtu return module_name_match 426*9341e7e3Sxiaofeibao-xjtu 427*9341e7e3Sxiaofeibao-xjtu def from_module_name(self, module_name): 428*9341e7e3Sxiaofeibao-xjtu self.name = module_name 429*9341e7e3Sxiaofeibao-xjtu module_name_match = self.match_module_name(self.name) 430*9341e7e3Sxiaofeibao-xjtu assert(module_name_match is not None) 431*9341e7e3Sxiaofeibao-xjtu num_ports = int(module_name_match.group(1)) 432*9341e7e3Sxiaofeibao-xjtu self.depth = int(module_name_match.group(2)) 433*9341e7e3Sxiaofeibao-xjtu self.width = int(module_name_match.group(3)) 434*9341e7e3Sxiaofeibao-xjtu self.mask_gran = int(module_name_match.group(4)) 435*9341e7e3Sxiaofeibao-xjtu assert(self.width % self.mask_gran == 0) 436*9341e7e3Sxiaofeibao-xjtu if num_ports == 1: 437*9341e7e3Sxiaofeibao-xjtu self.ports = self.SINGLE_PORT if self.mask_width() == 1 else self.SINGLE_PORT_MASK 438*9341e7e3Sxiaofeibao-xjtu else: 439*9341e7e3Sxiaofeibao-xjtu self.ports = self.DUAL_PORT if self.mask_width() == 1 else self.DUAL_PORT_MASK 440*9341e7e3Sxiaofeibao-xjtu self.has_multi_cycle = str(module_name_match.group(5)) != "" 441*9341e7e3Sxiaofeibao-xjtu self.has_repair = str(module_name_match.group(6)) != "" 442*9341e7e3Sxiaofeibao-xjtu 443*9341e7e3Sxiaofeibao-xjtu def ports_s(self): 444*9341e7e3Sxiaofeibao-xjtu s = { 445*9341e7e3Sxiaofeibao-xjtu self.SINGLE_PORT: "rw", 446*9341e7e3Sxiaofeibao-xjtu self.SINGLE_PORT_MASK: "mrw", 447*9341e7e3Sxiaofeibao-xjtu self.DUAL_PORT: "write,read", 448*9341e7e3Sxiaofeibao-xjtu self.DUAL_PORT_MASK: "mwrite,read" 449*9341e7e3Sxiaofeibao-xjtu } 450*9341e7e3Sxiaofeibao-xjtu return s[self.ports] 451*9341e7e3Sxiaofeibao-xjtu 452*9341e7e3Sxiaofeibao-xjtu def to_sram_conf_entry(self): 453*9341e7e3Sxiaofeibao-xjtu all_info = ["name", self.name, "depth", self.depth, "width", self.width, "ports", self.ports_s()] 454*9341e7e3Sxiaofeibao-xjtu if self.mask_gran < self.width: 455*9341e7e3Sxiaofeibao-xjtu all_info += ["mask_gran", self.mask_gran] 456*9341e7e3Sxiaofeibao-xjtu return " ".join(map(str, all_info)) 457*9341e7e3Sxiaofeibao-xjtu 458*9341e7e3Sxiaofeibao-xjtu def from_sram_conf_entry(self, line): 459*9341e7e3Sxiaofeibao-xjtu items = line.strip().split(" ") 460*9341e7e3Sxiaofeibao-xjtu self.name = items[1] 461*9341e7e3Sxiaofeibao-xjtu if items[7] == "rw": 462*9341e7e3Sxiaofeibao-xjtu ports = self.SINGLE_PORT 463*9341e7e3Sxiaofeibao-xjtu elif items[7] == "mrw": 464*9341e7e3Sxiaofeibao-xjtu ports = self.SINGLE_PORT_MASK 465*9341e7e3Sxiaofeibao-xjtu elif items[7] == "write,read": 466*9341e7e3Sxiaofeibao-xjtu ports = self.DUAL_PORT 467*9341e7e3Sxiaofeibao-xjtu elif items[7] == "mwrite,read": 468*9341e7e3Sxiaofeibao-xjtu ports = self.DUAL_PORT_MASK 469*9341e7e3Sxiaofeibao-xjtu else: 470*9341e7e3Sxiaofeibao-xjtu assert(0) 471*9341e7e3Sxiaofeibao-xjtu depth = int(items[3]) 472*9341e7e3Sxiaofeibao-xjtu width = int(items[5]) 473*9341e7e3Sxiaofeibao-xjtu mask_gran = int(items[-1]) if len(items) > 8 else width 474*9341e7e3Sxiaofeibao-xjtu matched_name = self.match_module_name(self.name) is not None 475*9341e7e3Sxiaofeibao-xjtu if matched_name: 476*9341e7e3Sxiaofeibao-xjtu self.from_module_name(self.name) 477*9341e7e3Sxiaofeibao-xjtu assert(self.ports == ports) 478*9341e7e3Sxiaofeibao-xjtu assert(self.depth == depth) 479*9341e7e3Sxiaofeibao-xjtu assert(self.width == width) 480*9341e7e3Sxiaofeibao-xjtu assert(self.mask_gran == mask_gran) 481*9341e7e3Sxiaofeibao-xjtu else: 482*9341e7e3Sxiaofeibao-xjtu self.ports = ports 483*9341e7e3Sxiaofeibao-xjtu self.depth = depth 484*9341e7e3Sxiaofeibao-xjtu self.width = width 485*9341e7e3Sxiaofeibao-xjtu self.mask_gran = mask_gran 486*9341e7e3Sxiaofeibao-xjtu 487*9341e7e3Sxiaofeibao-xjtu def to_sram_xlsx_entry(self, num_instances): 488*9341e7e3Sxiaofeibao-xjtu if self.is_single_port(): 489*9341e7e3Sxiaofeibao-xjtu num_read_port = "shared 1" 490*9341e7e3Sxiaofeibao-xjtu num_write_port = "shared 1" 491*9341e7e3Sxiaofeibao-xjtu read_clk = "RW0_clk" 492*9341e7e3Sxiaofeibao-xjtu write_clk = "RW0_clk" 493*9341e7e3Sxiaofeibao-xjtu else: 494*9341e7e3Sxiaofeibao-xjtu num_read_port = 1 495*9341e7e3Sxiaofeibao-xjtu num_write_port = 1 496*9341e7e3Sxiaofeibao-xjtu read_clk = "R0_clk" 497*9341e7e3Sxiaofeibao-xjtu write_clk = "W0_clk" 498*9341e7e3Sxiaofeibao-xjtu all_info = [self.name, num_instances, "SRAM", num_read_port, num_write_port, 0, 499*9341e7e3Sxiaofeibao-xjtu self.depth, self.width, self.mask_gran, read_clk, write_clk, "N/A"] 500*9341e7e3Sxiaofeibao-xjtu return all_info 501*9341e7e3Sxiaofeibao-xjtu 502*9341e7e3Sxiaofeibao-xjtu def get_foundry_sram_wrapper(self, mbist_type): 503*9341e7e3Sxiaofeibao-xjtu wrapper_type = "RAMSP" if self.is_single_port() else "RF2P" 504*9341e7e3Sxiaofeibao-xjtu wrapper_mask = "" if self.mask_width() == 1 else f"_M{self.mask_width()}" 505*9341e7e3Sxiaofeibao-xjtu wrapper_module = f"{wrapper_type}_{self.depth}x{self.width}{wrapper_mask}_WRAP" 506*9341e7e3Sxiaofeibao-xjtu wrapper_instance = "u_mem" 507*9341e7e3Sxiaofeibao-xjtu foundry_ports = { 508*9341e7e3Sxiaofeibao-xjtu "IP_RESET_B" : "mbist_IP_RESET_B", 509*9341e7e3Sxiaofeibao-xjtu "PWR_MGMT_IN" : "mbist_PWR_MGNT_IN", 510*9341e7e3Sxiaofeibao-xjtu "TRIM_FUSE_IN" : f"mbist_{mbist_type}_trim_fuse", 511*9341e7e3Sxiaofeibao-xjtu "SLEEP_FUSE_IN" : f"mbist_{mbist_type}_sleep_fuse", 512*9341e7e3Sxiaofeibao-xjtu "FSCAN_RAM_BYPSEL" : "mbist_bypsel", 513*9341e7e3Sxiaofeibao-xjtu "FSCAN_RAM_WDIS_B" : "mbist_wdis_b", 514*9341e7e3Sxiaofeibao-xjtu "FSCAN_RAM_RDIS_B" : "mbist_rdis_b", 515*9341e7e3Sxiaofeibao-xjtu "FSCAN_RAM_INIT_EN" : "mbist_init_en", 516*9341e7e3Sxiaofeibao-xjtu "FSCAN_RAM_INIT_VAL" : "mbist_init_val", 517*9341e7e3Sxiaofeibao-xjtu "FSCAN_CLKUNGATE" : "mbist_clkungate", 518*9341e7e3Sxiaofeibao-xjtu "OUTPUT_RESET" : "mbist_OUTPUT_RESET", 519*9341e7e3Sxiaofeibao-xjtu "PWR_MGMT_OUT" : "mbist_PWR_MGNT_OUT" 520*9341e7e3Sxiaofeibao-xjtu } 521*9341e7e3Sxiaofeibao-xjtu if self.is_single_port(): 522*9341e7e3Sxiaofeibao-xjtu foundry_ports["WRAPPER_CLK_EN"] = "mbist_WRAPPER_CLK_EN" 523*9341e7e3Sxiaofeibao-xjtu else: 524*9341e7e3Sxiaofeibao-xjtu foundry_ports["WRAPPER_WR_CLK_EN"] = "mbist_WRAPPER_WR_CLK_EN" 525*9341e7e3Sxiaofeibao-xjtu foundry_ports["WRAPPER_RD_CLK_EN"] = "mbist_WRAPPER_RD_CLK_EN" 526*9341e7e3Sxiaofeibao-xjtu if self.has_repair: 527*9341e7e3Sxiaofeibao-xjtu foundry_ports["ROW_REPAIR_IN"] = "repair_rowRepair" 528*9341e7e3Sxiaofeibao-xjtu foundry_ports["COL_REPAIR_IN"] = "repair_colRepair" 529*9341e7e3Sxiaofeibao-xjtu foundry_ports["io_bisr_shift_en"] = "mbist_bisr_shift_en" 530*9341e7e3Sxiaofeibao-xjtu foundry_ports["io_bisr_clock"] = "mbist_bisr_clock" 531*9341e7e3Sxiaofeibao-xjtu foundry_ports["io_bisr_reset"] = "mbist_bisr_reset" 532*9341e7e3Sxiaofeibao-xjtu foundry_ports["u_mem_bisr_inst_SI"] = "mbist_bisr_scan_in" 533*9341e7e3Sxiaofeibao-xjtu foundry_ports["u_mem_bisr_inst_SO"] = "mbist_bisr_scan_out" 534*9341e7e3Sxiaofeibao-xjtu if self.is_single_port(): 535*9341e7e3Sxiaofeibao-xjtu func_ports = { 536*9341e7e3Sxiaofeibao-xjtu "CK" : "RW0_clk", 537*9341e7e3Sxiaofeibao-xjtu "A" : "RW0_addr", 538*9341e7e3Sxiaofeibao-xjtu "WEN" : "RW0_en & RW0_wmode", 539*9341e7e3Sxiaofeibao-xjtu "D" : "RW0_wdata", 540*9341e7e3Sxiaofeibao-xjtu "REN" : "RW0_en & ~RW0_wmode", 541*9341e7e3Sxiaofeibao-xjtu "Q" : "RW0_rdata" 542*9341e7e3Sxiaofeibao-xjtu } 543*9341e7e3Sxiaofeibao-xjtu if self.mask_width() > 1: 544*9341e7e3Sxiaofeibao-xjtu func_ports["WM"] = "RW0_wmask" 545*9341e7e3Sxiaofeibao-xjtu else: 546*9341e7e3Sxiaofeibao-xjtu func_ports = { 547*9341e7e3Sxiaofeibao-xjtu "WCK" : "W0_clk", 548*9341e7e3Sxiaofeibao-xjtu "WA" : "W0_addr", 549*9341e7e3Sxiaofeibao-xjtu "WEN" : "W0_en", 550*9341e7e3Sxiaofeibao-xjtu "D" : "W0_data", 551*9341e7e3Sxiaofeibao-xjtu "RCK" : "R0_clk", 552*9341e7e3Sxiaofeibao-xjtu "RA" : "R0_addr", 553*9341e7e3Sxiaofeibao-xjtu "REN" : "R0_en", 554*9341e7e3Sxiaofeibao-xjtu "Q" : "R0_data" 555*9341e7e3Sxiaofeibao-xjtu } 556*9341e7e3Sxiaofeibao-xjtu if self.mask_width() > 1: 557*9341e7e3Sxiaofeibao-xjtu func_ports["WM"] = "W0_mask" 558*9341e7e3Sxiaofeibao-xjtu if self.width > 256: 559*9341e7e3Sxiaofeibao-xjtu func_ports["MBIST_SELECTEDOH"] = "mbist_selectedOH" 560*9341e7e3Sxiaofeibao-xjtu verilog_lines = [] 561*9341e7e3Sxiaofeibao-xjtu verilog_lines.append(f" {wrapper_module} {wrapper_instance} (\n") 562*9341e7e3Sxiaofeibao-xjtu connected_pins = [] 563*9341e7e3Sxiaofeibao-xjtu for pin_name in func_ports: 564*9341e7e3Sxiaofeibao-xjtu connected_pins.append(f".{pin_name}({func_ports[pin_name]})") 565*9341e7e3Sxiaofeibao-xjtu for pin_name in foundry_ports: 566*9341e7e3Sxiaofeibao-xjtu connected_pins.append(f".{pin_name}({foundry_ports[pin_name]})") 567*9341e7e3Sxiaofeibao-xjtu verilog_lines.append(" " + ",\n ".join(connected_pins) + "\n") 568*9341e7e3Sxiaofeibao-xjtu verilog_lines.append(" );\n") 569*9341e7e3Sxiaofeibao-xjtu return wrapper_module, "".join(verilog_lines) 570*9341e7e3Sxiaofeibao-xjtu 571*9341e7e3Sxiaofeibao-xjtudef generate_sram_conf(collection, module_prefix, out_dir): 572*9341e7e3Sxiaofeibao-xjtu if module_prefix is None: 573*9341e7e3Sxiaofeibao-xjtu module_prefix = "" 574*9341e7e3Sxiaofeibao-xjtu sram_conf = [] 575*9341e7e3Sxiaofeibao-xjtu sram_array_name = module_prefix + SRAMConfiguration.ARRAY_NAME 576*9341e7e3Sxiaofeibao-xjtu modules = collection.get_all_modules(match=sram_array_name) 577*9341e7e3Sxiaofeibao-xjtu for module in modules: 578*9341e7e3Sxiaofeibao-xjtu conf = SRAMConfiguration() 579*9341e7e3Sxiaofeibao-xjtu conf.from_module_name(module.get_name()[len(module_prefix):]) 580*9341e7e3Sxiaofeibao-xjtu sram_conf.append(conf) 581*9341e7e3Sxiaofeibao-xjtu conf_path = os.path.join(out_dir, "sram_configuration.txt") 582*9341e7e3Sxiaofeibao-xjtu with open(conf_path, "w") as f: 583*9341e7e3Sxiaofeibao-xjtu for conf in sram_conf: 584*9341e7e3Sxiaofeibao-xjtu f.write(conf.to_sram_conf_entry() + "\n") 585*9341e7e3Sxiaofeibao-xjtu return conf_path 586*9341e7e3Sxiaofeibao-xjtu 587*9341e7e3Sxiaofeibao-xjtudef create_sram_xlsx(out_dir, collection, sram_conf, top_module, try_prefix=None): 588*9341e7e3Sxiaofeibao-xjtu workbook = xlsxwriter.Workbook(os.path.join(out_dir, "sram_list.xlsx")) 589*9341e7e3Sxiaofeibao-xjtu worksheet = workbook.add_worksheet() 590*9341e7e3Sxiaofeibao-xjtu # Header for the list. Starting from row 5. 591*9341e7e3Sxiaofeibao-xjtu row = 5 592*9341e7e3Sxiaofeibao-xjtu columns = ["Array Instance Name", "# Instances", "Memory Type", 593*9341e7e3Sxiaofeibao-xjtu "# Read Ports", "# Write Ports", "# CAM Ports", 594*9341e7e3Sxiaofeibao-xjtu "Depth (Entries)", "Width (Bits)", "# Write Segments", 595*9341e7e3Sxiaofeibao-xjtu "Read Clk Pin Names(s)", "Write Clk Pin Name(s)", "CAM Clk Pin Name" 596*9341e7e3Sxiaofeibao-xjtu ] 597*9341e7e3Sxiaofeibao-xjtu for col, column_name in enumerate(columns): 598*9341e7e3Sxiaofeibao-xjtu worksheet.write(row, col, column_name) 599*9341e7e3Sxiaofeibao-xjtu row += 1 600*9341e7e3Sxiaofeibao-xjtu # Entries for the list. 601*9341e7e3Sxiaofeibao-xjtu total_size = 0 602*9341e7e3Sxiaofeibao-xjtu with open(sram_conf) as f: 603*9341e7e3Sxiaofeibao-xjtu for line in f: 604*9341e7e3Sxiaofeibao-xjtu conf = SRAMConfiguration() 605*9341e7e3Sxiaofeibao-xjtu conf.from_sram_conf_entry(line) 606*9341e7e3Sxiaofeibao-xjtu num_instances = collection.count_instances(top_module, conf.name) 607*9341e7e3Sxiaofeibao-xjtu if num_instances == 0 and try_prefix is not None: 608*9341e7e3Sxiaofeibao-xjtu try_prefix_name = f"{try_prefix}{conf.name}" 609*9341e7e3Sxiaofeibao-xjtu num_instances = collection.count_instances(top_module, try_prefix_name) 610*9341e7e3Sxiaofeibao-xjtu if num_instances != 0: 611*9341e7e3Sxiaofeibao-xjtu conf.name = try_prefix_name 612*9341e7e3Sxiaofeibao-xjtu all_info = conf.to_sram_xlsx_entry(num_instances) 613*9341e7e3Sxiaofeibao-xjtu for col, info in enumerate(all_info): 614*9341e7e3Sxiaofeibao-xjtu worksheet.write(row, col, info) 615*9341e7e3Sxiaofeibao-xjtu row += 1 616*9341e7e3Sxiaofeibao-xjtu total_size += conf.size() * num_instances 617*9341e7e3Sxiaofeibao-xjtu # Total size of the SRAM in top of the sheet 618*9341e7e3Sxiaofeibao-xjtu worksheet.write(0, 0, f"Total size: {total_size / (8 * 1024)} KiB") 619*9341e7e3Sxiaofeibao-xjtu workbook.close() 620*9341e7e3Sxiaofeibao-xjtu 621*9341e7e3Sxiaofeibao-xjtudef create_extra_files(out_dir, build_path): 622*9341e7e3Sxiaofeibao-xjtu extra_path = os.path.join(out_dir, "extra") 623*9341e7e3Sxiaofeibao-xjtu copytree("/nfs/home/share/southlake/extra", extra_path) 624*9341e7e3Sxiaofeibao-xjtu for f in os.listdir(build_path): 625*9341e7e3Sxiaofeibao-xjtu file_path = os.path.join(build_path, f) 626*9341e7e3Sxiaofeibao-xjtu if f.endswith(".csv"): 627*9341e7e3Sxiaofeibao-xjtu copy(file_path, extra_path) 628*9341e7e3Sxiaofeibao-xjtu 629*9341e7e3Sxiaofeibao-xjtudef replace_sram(out_dir, sram_conf, top_module, module_prefix): 630*9341e7e3Sxiaofeibao-xjtu replace_sram_dir = "memory_array" 631*9341e7e3Sxiaofeibao-xjtu replace_sram_path = os.path.join(out_dir, replace_sram_dir) 632*9341e7e3Sxiaofeibao-xjtu if not os.path.exists(replace_sram_path): 633*9341e7e3Sxiaofeibao-xjtu os.mkdir(replace_sram_path) 634*9341e7e3Sxiaofeibao-xjtu sram_wrapper_dir = "memory_wrapper" 635*9341e7e3Sxiaofeibao-xjtu sram_wrapper_path = os.path.join(out_dir, sram_wrapper_dir) 636*9341e7e3Sxiaofeibao-xjtu if not os.path.exists(sram_wrapper_path): 637*9341e7e3Sxiaofeibao-xjtu os.mkdir(sram_wrapper_path) 638*9341e7e3Sxiaofeibao-xjtu replaced_sram = [] 639*9341e7e3Sxiaofeibao-xjtu with open(sram_conf) as f: 640*9341e7e3Sxiaofeibao-xjtu for line in f: 641*9341e7e3Sxiaofeibao-xjtu conf = SRAMConfiguration() 642*9341e7e3Sxiaofeibao-xjtu conf.from_sram_conf_entry(line) 643*9341e7e3Sxiaofeibao-xjtu sim_sram_module = VModule(conf.name) 644*9341e7e3Sxiaofeibao-xjtu sim_sram_path = os.path.join(out_dir, top_module, f"{conf.name}.v") 645*9341e7e3Sxiaofeibao-xjtu if not os.path.exists(sim_sram_path) and module_prefix is not None: 646*9341e7e3Sxiaofeibao-xjtu sim_sram_path = os.path.join(out_dir, top_module, f"{module_prefix}{conf.name}.v") 647*9341e7e3Sxiaofeibao-xjtu sim_sram_module.name = f"{module_prefix}{conf.name}" 648*9341e7e3Sxiaofeibao-xjtu if not os.path.exists(sim_sram_path): 649*9341e7e3Sxiaofeibao-xjtu print(f"SRAM Replace: does not find {sim_sram_path}. Skipped.") 650*9341e7e3Sxiaofeibao-xjtu continue 651*9341e7e3Sxiaofeibao-xjtu with open(sim_sram_path, "r") as sim_f: 652*9341e7e3Sxiaofeibao-xjtu sim_sram_module.add_lines(sim_f.readlines()) 653*9341e7e3Sxiaofeibao-xjtu mbist_type = sim_sram_module.get_mbist_type() 654*9341e7e3Sxiaofeibao-xjtu wrapper, instantiation_v = conf.get_foundry_sram_wrapper(mbist_type) 655*9341e7e3Sxiaofeibao-xjtu sim_sram_module.replace_with_macro("FOUNDRY_MEM", instantiation_v) 656*9341e7e3Sxiaofeibao-xjtu output_file = os.path.join(replace_sram_path, f"{sim_sram_module.name}.v") 657*9341e7e3Sxiaofeibao-xjtu with open(output_file, "w") as f: 658*9341e7e3Sxiaofeibao-xjtu f.writelines(sim_sram_module.get_lines()) 659*9341e7e3Sxiaofeibao-xjtu # uncomment the following lines to copy the provided memory wrapper 660*9341e7e3Sxiaofeibao-xjtu # wrapper_dir = "/nfs/home/share/southlake/sram_replace/mem_wrap" 661*9341e7e3Sxiaofeibao-xjtu # wrapper_path = os.path.join(wrapper_dir, f"{wrapper}.v") 662*9341e7e3Sxiaofeibao-xjtu # copy(wrapper_path, os.path.join(sram_wrapper_path, f"{wrapper}.v")) 663*9341e7e3Sxiaofeibao-xjtu replaced_sram.append(sim_sram_module.name) 664*9341e7e3Sxiaofeibao-xjtu with open(os.path.join(out_dir, f"{sram_wrapper_dir}.f"), "w") as wrapper_f: 665*9341e7e3Sxiaofeibao-xjtu wrapper_f.write("// FIXME: include your SRAM wrappers here\n") 666*9341e7e3Sxiaofeibao-xjtu return replace_sram_dir, [f"-F {sram_wrapper_dir}.f"] 667*9341e7e3Sxiaofeibao-xjtu 668*9341e7e3Sxiaofeibao-xjtu 669*9341e7e3Sxiaofeibao-xjtudef replace_mbist_scan_controller(out_dir): 670*9341e7e3Sxiaofeibao-xjtu target_dir = "scan_mbist_ctrl" 671*9341e7e3Sxiaofeibao-xjtu target_path = os.path.join(out_dir, target_dir) 672*9341e7e3Sxiaofeibao-xjtu if not os.path.exists(target_path): 673*9341e7e3Sxiaofeibao-xjtu os.mkdir(target_path) 674*9341e7e3Sxiaofeibao-xjtu blackbox_src_dir = "/nfs/home/share/southlake/sram_replace/scan_mbist_ctrl_rpl_rtl" 675*9341e7e3Sxiaofeibao-xjtu for filename in os.listdir(blackbox_src_dir): 676*9341e7e3Sxiaofeibao-xjtu if filename.startswith("bosc_") and (filename.endswith(".v") or filename.endswith(".sv")): 677*9341e7e3Sxiaofeibao-xjtu copy(os.path.join(blackbox_src_dir, filename), target_path) 678*9341e7e3Sxiaofeibao-xjtu with open(os.path.join(out_dir, "dfx_blackbox.f"), "w") as wrapper_f: 679*9341e7e3Sxiaofeibao-xjtu wrapper_f.write("// FIXME: include your blackbox mbist/scan controllers here\n") 680*9341e7e3Sxiaofeibao-xjtu return target_dir, [f"-F dfx_blackbox.f"] 681*9341e7e3Sxiaofeibao-xjtu 682*9341e7e3Sxiaofeibao-xjtu 683*9341e7e3Sxiaofeibao-xjtuif __name__ == "__main__": 684*9341e7e3Sxiaofeibao-xjtu parser = argparse.ArgumentParser(description='Verilog parser for XS') 685*9341e7e3Sxiaofeibao-xjtu parser.add_argument('top', type=str, help='top-level module') 686*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--xs-home', type=str, help='path to XS') 687*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--config', type=str, default="Unknown", help='XSConfig') 688*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--prefix', type=str, help='module prefix') 689*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--ignore', type=str, default="", help='ignore modules (and their submodules)') 690*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--include', type=str, help='include verilog from more directories') 691*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--no-filelist', action='store_true', help='do not create filelist') 692*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--no-sram-conf', action='store_true', help='do not create sram configuration file') 693*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--no-sram-xlsx', action='store_true', help='do not create sram configuration xlsx') 694*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--with-extra-files', action='store_true', help='copy extra files') # for southlake alone 695*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--sram-replace', action='store_true', help='replace SRAM libraries') 696*9341e7e3Sxiaofeibao-xjtu parser.add_argument('--mbist-scan-replace', action='store_true', help='replace mbist and scan controllers') # for southlake alone 697*9341e7e3Sxiaofeibao-xjtu 698*9341e7e3Sxiaofeibao-xjtu args = parser.parse_args() 699*9341e7e3Sxiaofeibao-xjtu 700*9341e7e3Sxiaofeibao-xjtu xs_home = args.xs_home 701*9341e7e3Sxiaofeibao-xjtu if xs_home is None: 702*9341e7e3Sxiaofeibao-xjtu xs_home = os.path.realpath(os.getenv("NOOP_HOME")) 703*9341e7e3Sxiaofeibao-xjtu assert(xs_home is not None) 704*9341e7e3Sxiaofeibao-xjtu build_path = os.path.join(xs_home, "build") 705*9341e7e3Sxiaofeibao-xjtu files = get_files(build_path) 706*9341e7e3Sxiaofeibao-xjtu if args.include is not None: 707*9341e7e3Sxiaofeibao-xjtu for inc_path in args.include.split(","): 708*9341e7e3Sxiaofeibao-xjtu files += get_files(inc_path) 709*9341e7e3Sxiaofeibao-xjtu 710*9341e7e3Sxiaofeibao-xjtu top_module = args.top 711*9341e7e3Sxiaofeibao-xjtu module_prefix = args.prefix 712*9341e7e3Sxiaofeibao-xjtu config = args.config 713*9341e7e3Sxiaofeibao-xjtu ignore_modules = list(filter(lambda x: x != "", args.ignore.split(","))) 714*9341e7e3Sxiaofeibao-xjtu if module_prefix is not None: 715*9341e7e3Sxiaofeibao-xjtu top_module = f"{module_prefix}{top_module}" 716*9341e7e3Sxiaofeibao-xjtu ignore_modules += list(map(lambda x: module_prefix + x, ignore_modules)) 717*9341e7e3Sxiaofeibao-xjtu 718*9341e7e3Sxiaofeibao-xjtu print(f"Top-level Module: {top_module} with prefix {module_prefix}") 719*9341e7e3Sxiaofeibao-xjtu print(f"Config: {config}") 720*9341e7e3Sxiaofeibao-xjtu print(f"Ignored modules: {ignore_modules}") 721*9341e7e3Sxiaofeibao-xjtu collection, out_dir = create_verilog(files, top_module, config, try_prefix=module_prefix, ignore_modules=ignore_modules) 722*9341e7e3Sxiaofeibao-xjtu assert(collection) 723*9341e7e3Sxiaofeibao-xjtu 724*9341e7e3Sxiaofeibao-xjtu rtl_dirs = [top_module] 725*9341e7e3Sxiaofeibao-xjtu extra_filelist_lines = [] 726*9341e7e3Sxiaofeibao-xjtu if args.mbist_scan_replace: 727*9341e7e3Sxiaofeibao-xjtu dfx_ctrl, extra_dfx_lines = replace_mbist_scan_controller(out_dir) 728*9341e7e3Sxiaofeibao-xjtu rtl_dirs = [dfx_ctrl] + rtl_dirs 729*9341e7e3Sxiaofeibao-xjtu extra_filelist_lines += extra_dfx_lines 730*9341e7e3Sxiaofeibao-xjtu if not args.no_filelist: 731*9341e7e3Sxiaofeibao-xjtu create_filelist(top_module, out_dir, rtl_dirs, extra_filelist_lines) 732*9341e7e3Sxiaofeibao-xjtu if not args.no_sram_conf: 733*9341e7e3Sxiaofeibao-xjtu sram_conf = generate_sram_conf(collection, module_prefix, out_dir) 734*9341e7e3Sxiaofeibao-xjtu if not args.no_sram_xlsx: 735*9341e7e3Sxiaofeibao-xjtu create_sram_xlsx(out_dir, collection, sram_conf, top_module, try_prefix=module_prefix) 736*9341e7e3Sxiaofeibao-xjtu if args.sram_replace: 737*9341e7e3Sxiaofeibao-xjtu sram_replace_dir, sram_extra_lines = replace_sram(out_dir, sram_conf, top_module, module_prefix) 738*9341e7e3Sxiaofeibao-xjtu # We create another filelist for foundry-provided SRAMs 739*9341e7e3Sxiaofeibao-xjtu if not args.no_filelist: 740*9341e7e3Sxiaofeibao-xjtu rtl_dirs = [sram_replace_dir] + rtl_dirs 741*9341e7e3Sxiaofeibao-xjtu extra_filelist_lines += sram_extra_lines 742*9341e7e3Sxiaofeibao-xjtu create_filelist(f"{top_module}_with_foundry_sram", out_dir, rtl_dirs, extra_filelist_lines) 743*9341e7e3Sxiaofeibao-xjtu if args.with_extra_files: 744*9341e7e3Sxiaofeibao-xjtu create_extra_files(out_dir, build_path) 745