def check_results(ckt_name): ckt_name_json = ckt_name if not ckt_name.endswith('.json'): ckt_name_json += '.json' with open(ckt_name_json, "rt") as fp: d = json.load(fp) layers = [f'M{k}' for k in range(7)] + [f'V{k}' for k in range(6)] p = re.compile("^(.*)_gr$") terminals = [] for term in d['terminals']: if term['layer'] not in layers: continue nm = term['netName'] if nm is not None and p.match(nm): continue # # !kor and !float signals might be need. Right now, just excluding them. # if nm in ['!kor', '!float']: continue terminals.append(term) d['terminals'] = terminals cnv = IntelP1276p31canvas() cnv.bbox = transformation.Rect(*d['bbox']) cnv.terminals = d['terminals'] # data = cnv.gen_data(run_pex=True, run_drc=True, postprocess=True) with open(ckt_name + "_prim.json", "w") as fp: data = cnv.writeJSON(fp, postprocess=True) return data
def aux(fn): fpath = get_fpath(fn) with fpath.open("rt") as fp: d = json.load(fp) pdkdir = mydir.parent.parent / "pdks" / "FinFET14nm_Mock_PDK" generator = primitive.get_generator('MOSGenerator', pdkdir) # TODO: Remove these hardcoded widths & heights from __init__() # (Height may be okay since it defines UnitCellHeight) cnv = generator(pdk.Pdk().load(pdkdir / 'layers.json'), 12, 4, 2, 3) layer_map = { 'metal1': 'M1', 'metal2': 'M2', 'metal3': 'M3', 'metal4': 'M4', 'metal5': 'M5', 'metal6': 'M6', 'metal7': 'M7', 'via1': 'V1', 'via2': 'V2', 'via3': 'V3', 'via4': 'V4', 'via5': 'V5', 'via6': 'V6', } p_exclude = re.compile('^((.*_gr)|(!kor))$') terminals = [] for term in d["terminals"]: # crazy hack to remove two different via sizes if term['layer'] == 'V2': r = term['rect'] if r[2] - r[0] == 320: # make it be 400 r[0] -= 40 r[2] += 40 term['rect'] = r if term['layer'] in layer_map: term['layer'] = layer_map[term['layer']] if not p_exclude.match(term['netName']): terminals.append(term) d["terminals"] = terminals rational_scaling(d, div=5) cnv.bbox = transformation.Rect(*d["bbox"]) cnv.terminals = d["terminals"] # # We need to merge in the leaf cells # cnv.gen_data(run_pex=False) assert len(cnv.rd.shorts) == 0, pformat(cnv.rd.shorts) assert len(cnv.rd.opens) == 0, pformat(cnv.rd.opens) assert len(cnv.drc.errors) == 0, pformat(cnv.drc.errors)
def mos(canvas_gen, tx: Transistor, track_pattern=None): assert tx.nf % 2 == 0, f'Odd number of fingers are not allowed' c = canvas_gen() if tx.device_type == 'stack': c.addWire(c.m1, 'S', 'S', 1, (1, -1), (4, 1)) c.addWire(c.m1, 'D', 'D', 1 + tx.nf, (1, -1), (4, 1)) else: for x in range(1, 2 + tx.nf): p = 'D' if x % 2 == 0 else 'S' c.addWire(c.m1, p, p, x, (1, -1), (4, 1)) for x in range(2, 1 + tx.nf, 2): c.addWire(c.m1, 'G', 'G', x, (5, -1), (6, 1)) if track_pattern is not None: if 'G' in track_pattern: for y in track_pattern['G']: if tx.nf > 2: g_b_idx = (2, -1) g_e_idx = (tx.nf, 1) else: g_b_idx = (1, -1) g_e_idx = (1 + tx.nf, 1) c.addWire(c.m2, 'G', 'G', y, g_b_idx, g_e_idx) if tx.device_type == 'stack': s_b_idx = (1, -1) s_e_idx = (2, 1) d_b_idx = (tx.nf, -1) d_e_idx = (1 + tx.nf, 1) else: s_b_idx = (1, -1) s_e_idx = (1 + tx.nf, 1) d_b_idx = (1, -1) d_e_idx = (1 + tx.nf, 1) if 'S' in track_pattern: for y in track_pattern['S']: c.addWire(c.m2, 'S', 'S', y, s_b_idx, s_e_idx) if 'D' in track_pattern: for y in track_pattern['D']: c.addWire(c.m2, 'D', 'D', y, d_b_idx, d_e_idx) c.drop_via(c.v1) # Precomputed bounding box x1 = c.m1.clg.value(2 + tx.nf) y1 = c.m2.clg.value(7) r = [0, 0, x1[0], y1[0]] c.bbox = transformation.Rect(*r) return {"bbox": c.bbox.toList(), "instance": {}, "terminals": c.terminals}
def import_result(name): if not name.endswith('.json'): name += '.json' with open(name, "rt") as fp: d = json.load(fp) layer_tbl = { "tcn": "Diffcon", "gcn": "Polycon", "diffcon": "Diffcon", "polycon": "Polycon", "nwell": "Nwell", "ndiff": "Ndiff", "pdiff": "Pdiff", "metal1": "M1", "metal2": "M2", "metal3": "M3", "metal4": "M4", "metal5": "M5", "via0": "V0", "via1": "V1", "via2": "V2", "via3": "V3", "via4": "V4" } p = re.compile("^(.*)_gr$") def s(r): assert all(v % 10 == 0 for v in r) return [v // 10 for v in r] terminals = [] for term in d['terminals']: ly = term['layer'] nm = term['netName'] if 'netName' in term else term['net_name'] if nm is not None and p.match(nm): continue term['layer'] = layer_tbl.get(ly, ly) term['rect'] = s(term['rect']) # SY: Remove net_name from boundary terminals for improve viewing if str(term['layer']).lower() == 'boundary': net_name = 'netName' if 'netName' in term else 'net_name' term[net_name] = None terminals.append(term) d['terminals'] = terminals cnv = IntelP1222p2Canvas() cnv.bbox = transformation.Rect(*s(d['bbox'])) cnv.terminals = d['terminals'] return (cnv)
def place(self, rows): # keep record of what x, y, sx, sy the instance is stamped x_offset = y_offset = 0 for row in rows: x_offset = 0 for device in row: [cell, instance_name, pin_map, flip_x] = device self.stamp_cell(cell, instance_name, pin_map, x_offset, y_offset, flip_x) x_offset += cell['bbox'][2] - cell['bbox'][0] y_offset += cell['bbox'][3] - cell['bbox'][1] self.bbox = transformation.Rect(*[0, 0, x_offset, y_offset]) print(self.bbox)
def place(self, rows): x_offset = 0 y_offset = 0 x_offset += 0*self.pdk['Poly']['Pitch'] # whitespace for feol rules for row in rows: x_offset = 0 for device in row: [cell, instance_name, pin_map, flip_x] = device self.stamp_cell(cell, instance_name, pin_map, x_offset, y_offset, flip_x) x_offset += cell['bbox'][2] - cell['bbox'][0] y_offset += cell['bbox'][3] - cell['bbox'][1] x_offset += 0*self.pdk['Poly']['Pitch'] # whitespace for feol rules self.bbox = transformation.Rect(*[0, 0, x_offset, y_offset]) logger_func(f'bounding box: {self.bbox}')
def test_remove_duplicates(fn): with (rdir / fn).open("rt") as fp: d = json.load(fp) pdkdir = pathlib.Path( __file__).parent.parent.parent / "pdks" / "FinFET14nm_Mock_PDK" generator = primitive.get_generator('MOSGenerator', pdkdir) # TODO: Remove these hardcoded widths & heights from __init__() # (Height may be okay since it defines UnitCellHeight) cnv = generator(pdk.Pdk().load(pdkdir / 'layers.json'), 12, 4, 2, 3) cnv.bbox = transformation.Rect(*d["bbox"]) cnv.terminals = d["terminals"] cnv.gen_data(run_pex=False) assert len(cnv.rd.different_widths) == 0, pformat(cnv.rd.different_widths) assert len(cnv.rd.shorts) == 0, pformat(cnv.rd.shorts) # assert len(cnv.rd.opens) == 0, pformat(cnv.rd.opens) assert len(cnv.drc.errors) == 0, pformat(cnv.drc.errors)
def tap(canvas_gen, tx: Transistor): assert tx.nf % 2 == 0, f'Odd number of fingers are not allowed' c = canvas_gen() c.addWire(c.m1, 'B', 'B', 1, (2, -1), (5, 1)) c.addWire(c.m1, 'B', 'B', 1 + tx.nf, (2, -1), (5, 1)) c.addWire(c.m2, 'B', 'B', 2, (1, -1), (1 + tx.nf, 1)) c.addWire(c.m2, 'B', 'B', 5, (1, -1), (1 + tx.nf, 1)) c.drop_via(c.v1) # Precomputed bounding box x1 = c.m1.clg.value(2 + tx.nf) y1 = c.m2.clg.value(7) r = [0, 0, x1[0], y1[0]] c.bbox = transformation.Rect(*r) return {"bbox": c.bbox.toList(), "instance": {}, "terminals": c.terminals}
def mos(tx: Transistor): assert tx.nf % 2 == 0, f'Odd number of fingers are not allowed in this PDK.' # TODO: Below is an example of parameters to instantiate a PCELL # When flow is completed, instance is used to stamp the PCELLs where instantiated params = ' '.join([f'(\"dev_type\" \"string\" \"{tx.device_type}\")', f'(\"vt_type\" \"string\" \"{tx.model_name}\")', f'(\"nfin\" \"string\" \"{tx.nfin}\")' f'(\"nf\" \"string\" \"{tx.nf}\")' ]) instance = {"library": "pdk_library", "cell": "pdk_mos", "view": "layout", "params": f'({params})'}, c = CanvasPDK() if tx.device_type == 'stack': c.addWire(c.M1, 'S', 'S', 1, (0, 1), (3, 3)) c.addWire(c.M1, 'D', 'D', 1+tx.nf, (0, 1), (3, 3)) else: for x in range(1, 2+tx.nf): p = 'D' if x % 2 == 0 else 'S' c.addWire(c.M1, p, p, x, (0, 1), (3, 3)) for x in range(2, 1+tx.nf, 2): c.addWire(c.M1, 'G', 'G', x, (4, 1), (5, 3)) # for x in range(0, 8): # c.addWire(c.M2, None, None, x, (0, 1), (6, 1)) # Precomputed bounding box # rx = c.M1.segment(None, None, 2+tx.nf, (0, 1), (1, 3)) # ry = c.M2.segment(None, None, 7, (0, 1), (1, 3)) x1 = c.M1.clg.value(2+tx.nf) y1 = c.M2.clg.value(7) r = [0, 0, x1[0], y1[0]] c.bbox = transformation.Rect(*r) # c.computeBbox() return {"bbox": c.bbox.toList(), "instance": instance, "terminals": c.terminals}
def s(r): assert all(v % 10 == 0 for v in r) return [v // 10 for v in r] terminals = [] for term in d['terminals']: ly = term['layer'] if ly in skip_layers: continue nm = term['netName'] if 'netName' in term else term['net_name'] if nm is not None and p.match(nm): continue term['layer'] = layer_tbl.get(ly, ly) term['rect'] = s(term['rect']) terminals.append(term) d['terminals'] = terminals pdkfile = pathlib.Path('Intel/Intel_P1222p2_PDK/layers.json') cnv = IntelP1222p2Canvas(pdkfile) cnv.bbox = transformation.Rect(*s(d['bbox'])) cnv.terminals = d['terminals'] cnv.gen_data(run_pex=False) if False: assert len(cnv.rd.different_widths) == 0, pformat( cnv.rd.different_widths) assert len(cnv.rd.shorts) == 0, pformat(cnv.rd.shorts) assert len(cnv.rd.opens) == 0, pformat(cnv.rd.opens) assert len(cnv.drc.errors) == 0, pformat(cnv.drc.errors)
def check_results(ckt_name): ckt_name_json = ckt_name if not ckt_name.endswith('.json'): ckt_name_json += '.json' with open(ckt_name_json, "rt") as fp: d = json.load(fp) skip_layers = set([ "boundary", "diearea", "cellarea", "ndiff", "pdiff", "nwell", "poly", "gcn", "tcn", "polycon", "diffcon" ]) layer_tbl = { "diffcon": "Diffcon", "polycon": "Polycon", "nwell": "Nwell", "metal1": "M1", "metal2": "M2", "metal3": "M3", "metal4": "M4", "metal5": "M5", "via0": "V0", "via1": "V1", "via2": "V2", "via3": "V3", "via4": "V4" } p = re.compile("^(.*)_gr$") def s(r): assert all(v % 10 == 0 for v in r) return [v // 10 for v in r] terminals = [] for term in d['terminals']: ly = term['layer'] if str(ly).lower() in skip_layers: continue nm = term['netName'] if 'netName' in term else term['net_name'] # # !kor and !float signals might be need. Right now, just excluding them. # if nm in ['!kor', '!float']: continue if nm is not None and p.match(nm): continue term['layer'] = layer_tbl.get(ly, ly) term['rect'] = s(term['rect']) terminals.append(term) d['terminals'] = terminals cnv = IntelP1222p2Canvas() cnv.bbox = transformation.Rect(*s(d['bbox'])) cnv.terminals = d['terminals'] data = cnv.gen_data(run_pex=True, run_drc=True) with open(ckt_name + "_prim.json", "w") as fp: cnv.writeJSON(fp) tbl = cnv.pex.getSummaryCaps() def diffs(n0, n1): a, b = tbl[n0], tbl[n1] s = (a + b) / 2 return f"{n0},{n1}: {a:.2f}f, {b:.2f}f, {100*(a/s-1):.1f}%, {100*(b/s-1):.1f}%" if ckt_name.startswith('comp'): print(diffs('vin', 'vip')) print(diffs('vin_d', 'vip_d')) print(diffs('vin_o', 'vip_o')) print(diffs('von', 'vop')) if False: assert len(cnv.rd.different_widths) == 0, pformat( cnv.rd.different_widths) assert len(cnv.rd.shorts) == 0, pformat(cnv.rd.shorts) assert len(cnv.rd.opens) == 0, pformat(cnv.rd.opens) assert len(cnv.drc.errors) == 0, pformat(cnv.drc.errors) return (data)