From b90f5c9a59e6c1611600400b286fbff555282b8b Mon Sep 17 00:00:00 2001 From: Michael Timothy Grimes Date: Thu, 8 Feb 2018 14:21:15 -0800 Subject: [PATCH] pbitcell is now a multiport cell with a read transistor that connects to RBL and RROW and a read access transistor that connects to Q and gnd current commit works without drc errors on freepdk45 but has drc rules not included in scn3me_subm. Does have lvs errors adding several unit tests: the basic one that tests the full functionality of the pbitcell, one with no write ports, and one with no read ports --- compiler/pbitcell.py | 685 ++++++++++++++------------ compiler/tests/04_pbitcell_0R_test.py | 60 +++ compiler/tests/04_pbitcell_0W_test.py | 60 +++ compiler/tests/04_pbitcell_test.py | 4 +- 4 files changed, 486 insertions(+), 323 deletions(-) create mode 100644 compiler/tests/04_pbitcell_0R_test.py create mode 100644 compiler/tests/04_pbitcell_0W_test.py diff --git a/compiler/pbitcell.py b/compiler/pbitcell.py index 40c82343..86bc5e9d 100644 --- a/compiler/pbitcell.py +++ b/compiler/pbitcell.py @@ -9,26 +9,29 @@ from globals import OPTS class pbitcell(design.design): """ - This module implements a parametrically sized multi-port bitcell. + This module implements a parametrically sized multi-port bitcell """ - def __init__(self): + def __init__(self, num_write=1, num_read=1): name = "pbitcell" design.design.__init__(self, name) - debug.info(2, "create a multi-port bitcell") + debug.info(2, "create a multi-port bitcell with {0} write ports and {1} read ports".format(num_write, num_read)) - self.num_write = 2 - self.num_read = 2 + self.num_write = num_write + self.num_read = num_read self.create_layout() self.DRC_LVS() def add_pins(self): - self.add_pin("WROW") - self.add_pin("WBL") - self.add_pin("WBL_bar") + for k in range(0,self.num_write): + self.add_pin("WROW{}".format(k)) + for k in range(0,self.num_write): + self.add_pin("WBL{}".format(k)) + self.add_pin("WBL_bar{}".format(k)) for k in range(0,self.num_read): self.add_pin("RROW{}".format(k)) + for k in range(0,self.num_read): self.add_pin("RBL{}".format(k)) self.add_pin("RBL_bar{}".format(k)) self.add_pin("vdd") @@ -37,67 +40,127 @@ class pbitcell(design.design): def create_layout(self): self.create_ptx() self.add_storage() - self.add_rails() - self.add_write_transistors() - self.add_read_transistors() + self.add_rails() + if(self.num_write > 0): + self.add_write_transistors() + if(self.num_read > 0): + self.add_read_transistors() self.extend_well() #self.add_fail() def create_ptx(self): - """ - Create ptx all transistors. Also define measurements to be used throughout bitcell. - """ - self.i_nmos = ptx(width=2.3*parameter["min_tx_size"], - tx_type="nmos", - connect_active=True, - connect_poly=True) + """ Create ptx for all transistors. Also define measurements to be used throughout bitcell """ + # create ptx for inverter transistors + self.i_nmos = ptx(width=2*parameter["min_tx_size"], + tx_type="nmos", + connect_active=True, + connect_poly=True) self.add_mod(self.i_nmos) self.i_pmos = ptx(width=parameter["min_tx_size"], - tx_type="pmos", - connect_active=True, - connect_poly=True) + tx_type="pmos", + connect_active=True, + connect_poly=True) self.add_mod(self.i_pmos) # create ptx for write transitors - self.w_nmos = ptx(width=1.5*parameter["min_tx_size"], - tx_type="nmos", - connect_active=True, - connect_poly=True) + self.w_nmos = ptx(width=parameter["min_tx_size"], + tx_type="nmos", + connect_active=True, + connect_poly=True) self.add_mod(self.w_nmos) # create ptx for read transistors - self.r_nmos = ptx(width=parameter["min_tx_size"], - tx_type="nmos", - connect_active=True, - connect_poly=True) + self.r_nmos = ptx(width=2*parameter["min_tx_size"], + mults=2, + tx_type="nmos", + connect_active=False, + connect_poly=False) self.add_mod(self.r_nmos) - # determine metal contact extentions - self.in_ex = 0.5*(self.i_nmos.active_contact.height - self.i_nmos.active_height) + # determine metal contact extensions self.ip_ex = 0.5*(self.i_pmos.active_contact.height - self.i_pmos.active_height) - self.w_ex = 0.5*(self.w_nmos.active_contact.height - self.w_nmos.active_height) - self.r_ex = 0.5*(self.r_nmos.active_contact.height - self.r_nmos.active_height) + self.w_ex = 0.5*(self.w_nmos.active_contact.height - self.w_nmos.active_height) # determine global measurements - spacer = 5*drc["minwidth_metal2"] + self.w_ex + self.r_ex + w_spacer = drc["minwidth_metal2"] + self.w_ex + contact.poly.width + drc["poly_to_field_poly"] + drc["poly_extend_active"] + r_spacer = 2*drc["minwidth_poly"] + drc["minwidth_metal1"] + 2*contact.poly.width + rw_spacer = drc["minwidth_poly"] + drc["poly_to_field_poly"] + drc["minwidth_metal2"] + 2*contact.poly.width + self.w_ex - self.w_tile_width = 3*parameter["min_tx_size"] + self.w_nmos.active_height - self.r_tile_width = 3*parameter["min_tx_size"] + self.r_nmos.active_height - self.inv_gap = 5*contact.poly.width - self.leftmost_xpos = -(self.i_nmos.active_width + 1.5*parameter["min_tx_size"] + drc["well_enclosure_active"]) \ - - self.num_write*(3*parameter["min_tx_size"] + self.w_nmos.active_height) \ - - (self.num_read-1)*(3*parameter["min_tx_size"] + self.r_nmos.active_height) - spacer - self.r_nmos.active_height + self.w_tile_width = w_spacer + self.w_nmos.active_height + self.r_tile_width = r_spacer + self.r_nmos.active_height + self.inv_gap = drc["poly_to_active"] + drc["poly_to_field_poly"] + 2*contact.poly.width + drc["minwidth_metal1"] + self.ip_ex + self.cross_heightL = self.i_nmos.active_height + drc["poly_to_active"] + 0.5*contact.poly.width + self.cross_heightU = self.i_nmos.active_height + drc["poly_to_active"] + drc["poly_to_field_poly"] + 1.5*contact.poly.width + + self.leftmost_xpos = -(self.i_nmos.active_width + 1.5*parameter["min_tx_size"]) \ + - self.num_write*(w_spacer + self.w_nmos.active_height) \ + - rw_spacer - self.r_nmos.active_height - (self.num_read-1)*self.r_tile_width \ + - 3*drc["minwidth_metal1"] self.botmost_ypos = -2*drc["minwidth_metal1"] - self.num_write*2*drc["minwidth_metal2"] - self.num_read*2*drc["minwidth_metal2"] self.topmost_ypos = self.inv_gap + self.i_nmos.active_height + self.i_pmos.active_height + drc["poly_extend_active"] + 2*drc["minwidth_metal1"] self.cell_width = -2*self.leftmost_xpos self.cell_height = self.topmost_ypos - self.botmost_ypos - - + + + def add_storage(self): + """ + Creates the crossed coupled inverters that act as storage for the bitcell. + """ + lit_xpos = -(self.i_nmos.active_width + 1.5*parameter["min_tx_size"]) + rit_xpos = 1.5*parameter["min_tx_size"] + it_ypos = self.inv_gap + self.i_nmos.active_height + + # create active + self.i_nmosL = self.add_inst(name="i_nmosL", + mod=self.i_nmos, + offset=[lit_xpos,0]) + self.connect_inst(["Q_bar", "Q", "gnd", "gnd"]) + + self.i_nmosR = self.add_inst(name="i_nmosR", + mod=self.i_nmos, + offset=[rit_xpos,0]) + self.connect_inst(["gnd", "Q_bar", "Q", "gnd"]) + + self.i_pmosL = self.add_inst(name="i_pmosL", + mod=self.i_pmos, + offset=[lit_xpos, it_ypos]) + self.connect_inst(["Q_bar", "Q", "vdd", "vdd"]) + + self.i_pmosR = self.add_inst(name="i_pmosR", + mod=self.i_pmos, + offset=[rit_xpos, it_ypos]) + self.connect_inst(["vdd", "Q_bar", "Q", "vdd"]) + + # connect poly for inverters + self.add_path("poly", [self.i_nmosL.get_pin("G").uc(), self.i_pmosL.get_pin("G").bc()]) + self.add_path("poly", [self.i_nmosR.get_pin("G").uc(), self.i_pmosR.get_pin("G").bc()]) + + # connect drains for inverters + self.add_path("metal1", [self.i_nmosL.get_pin("D").uc(), self.i_pmosL.get_pin("D").bc()]) + self.add_path("metal1", [self.i_nmosR.get_pin("S").uc(), self.i_pmosR.get_pin("S").bc()]) + + # add contacts to connect gate poly to drain/source metal1 (to connect Q to Q_bar) + offsetL = vector(self.i_nmosL.get_pin("G").rc().x + drc["poly_to_field_poly"] + 0.5*contact.poly.width, self.cross_heightU) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetL, + rotate=90) + + offsetR = vector(self.i_nmosR.get_pin("G").lc().x - drc["poly_to_field_poly"] - 0.5*contact.poly.width, self.cross_heightL) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetR, + rotate=90) + + # connect contacts to gate poly (cross couple) + gate_offsetR = vector(self.i_nmosR.get_pin("G").lc().x, offsetL.y) + self.add_path("poly", [offsetL, gate_offsetR]) + + gate_offsetL = vector(self.i_nmosL.get_pin("G").rc().x, offsetR.y) + self.add_path("poly", [offsetR, gate_offsetL]) + + def add_rails(self): - """ - Adds rails for vdd and gnd. - """ + """ Add rails for vdd and gnd """ self.gnd_position = vector(self.leftmost_xpos, -2*drc["minwidth_metal1"]) self.gnd = self.add_layout_pin(text="gnd", layer="metal1", @@ -111,112 +174,27 @@ class pbitcell(design.design): offset=self.vdd_position, width=self.cell_width, height=drc["minwidth_metal1"]) - - # connect sources to rails - # connect nmos to gnd - i_nmosL_source = self.i_nmosL.get_pin("S").bc() - gnd_posL = vector(self.i_nmosL.get_pin("S").bc().x, self.gnd_position.y + drc["minwidth_metal1"]) - self.add_path("metal1", [i_nmosL_source, gnd_posL]) - i_nmosR_drain = self.i_nmosR.get_pin("D").bc() + """ Connect inverters to rails """ + # connect nmos to gnd + gnd_posL = vector(self.i_nmosL.get_pin("S").bc().x, self.gnd_position.y + drc["minwidth_metal1"]) + self.add_path("metal1", [self.i_nmosL.get_pin("S").bc(), gnd_posL]) + gnd_posR = vector(self.i_nmosR.get_pin("D").bc().x, self.gnd_position.y + drc["minwidth_metal1"]) - self.add_path("metal1", [i_nmosR_drain, gnd_posR]) + self.add_path("metal1", [self.i_nmosR.get_pin("D").bc(), gnd_posR]) # connect pmos to vdd - i_pmosL_source = self.i_pmosL.get_pin("S").uc() vdd_posL = vector(self.i_nmosL.get_pin("S").uc().x, self.vdd_position.y) - self.add_path("metal1", [i_pmosL_source, vdd_posL]) + self.add_path("metal1", [self.i_pmosL.get_pin("S").uc(), vdd_posL]) - i_pmosR_drain = self.i_pmosR.get_pin("D").uc() vdd_posR = vector(self.i_nmosR.get_pin("D").uc().x, self.vdd_position.y) - self.add_path("metal1", [i_pmosR_drain, vdd_posR]) + self.add_path("metal1", [self.i_pmosR.get_pin("D").uc(), vdd_posR]) - - def add_storage(self): - """ - Creates the crossed coupled inverters that act as storage for the bitcell. - """ - # calculate offsets - lit_xpos = -(self.i_nmos.active_width + 1.5*parameter["min_tx_size"]) - rit_xpos = 1.5*parameter["min_tx_size"] - it_ypos = self.inv_gap + self.i_nmos.active_height - - - # create active - self.i_nmosL = self.add_inst(name="i_nmosL", - mod=self.i_nmos, - offset=[lit_xpos,0]) - self.connect_inst(["IR", "IL", "gnd", "gnd"]) - - self.i_nmosR = self.add_inst(name="i_nmosR", - mod=self.i_nmos, - offset=[rit_xpos,0]) - self.connect_inst(["IL", "IR", "gnd", "gnd"]) - self.i_pmosL = self.add_inst(name="i_pmosL", - mod=self.i_pmos, - offset=[lit_xpos, it_ypos]) - self.connect_inst(["IL", "IR", "vdd", "vdd"]) - - self.i_pmosR = self.add_inst(name="i_pmosR", - mod=self.i_pmos, - offset=[rit_xpos, it_ypos]) - self.connect_inst(["IL", "IR", "vdd", "vdd"]) - - - # connect poly for inverters - i_nmosL_poly = self.i_nmosL.get_pin("G").uc() - i_pmosL_poly = self.i_pmosL.get_pin("G").bc() - self.add_path("poly", [i_nmosL_poly, i_pmosL_poly]) - - i_nmosR_poly = self.i_nmosR.get_pin("G").uc() - i_pmosR_poly = self.i_pmosR.get_pin("G").bc() - self.add_path("poly", [i_nmosR_poly, i_pmosR_poly]) - - - # connect drains for inverters - i_nmosL_drain = self.i_nmosL.get_pin("D").uc() - i_pmosL_drain = self.i_pmosL.get_pin("D").bc() - self.add_path("metal1", [i_nmosL_drain, i_pmosL_drain]) - - i_nmosR_source = self.i_nmosR.get_pin("S").uc() - i_pmosR_source = self.i_pmosR.get_pin("S").bc() - self.add_path("metal1", [i_nmosR_source, i_pmosR_source]) - - # add cross couple vias - offset = vector(self.i_nmosL.get_pin("D").ur().x + contact.poly.height, self.i_nmos.active_height + 0.6*self.inv_gap) - self.icl = self.add_contact(layers=("poly", "contact", "metal1"), - offset=offset, - rotate=90) - - offset = vector(self.i_nmosR.get_pin("S").ul().x, self.i_nmos.active_height + 0.2*self.inv_gap) - self.icr = self.add_contact(layers=("poly", "contact", "metal1"), - offset=offset, - rotate=90) - - - # connect vias to poly (cross couple) - correct = 0.5*(self.i_nmos.active_contact.width - drc["minwidth_metal1"]) - cross_width = 0.5*self.i_nmos.active_width - 0.5*drc["minwidth_poly"] + 3*parameter["min_tx_size"] + correct - offset = vector(self.i_nmosL.get_pin("G").ur().x, self.i_nmos.active_height + 0.2*self.inv_gap) - self.add_rect(layer="poly", - offset=offset, - width=cross_width, - height=contact.poly.width) - - offset = vector(self.i_nmosL.get_pin("D").ur().x, self.i_nmos.active_height + 0.6*self.inv_gap) - self.add_rect(layer="poly", - offset=offset, - width=cross_width, - height=contact.poly.width) - - def add_write_transistors(self): - """ - Define variables relevant to write transistors - """ + """ Define variables relevant to write transistors """ lit_xpos = -(self.i_nmos.active_width + 1.5*parameter["min_tx_size"]) - rit_xpos = 1.5*parameter["min_tx_size"] + rit_xpos = 1.5*parameter["min_tx_size"] + self.i_nmos.active_width rot_correct = self.w_nmos.active_height self.w_nmosL = [None] * self.num_write @@ -225,26 +203,27 @@ class pbitcell(design.design): self.wbl_positions = [None] * self.num_write self.wbl_bar_positions = [None] * self.num_write + for k in range(0,self.num_write): - """ - Add transistors and WROW lines - """ - wrow_ypos = -2*drc["minwidth_metal1"] - (k+1)*2*drc["minwidth_metal2"] - lwt_xpos = lit_xpos + rot_correct - (k+1)*self.w_tile_width - rwt_xpos = rit_xpos + self.i_nmos.active_width + 3*parameter["min_tx_size"] + rot_correct + k*self.w_tile_width + """ Add transistors and WROW lines """ + # calculate transistor offsets + w_spacer = drc["minwidth_metal2"] + self.w_ex + contact.poly.width + drc["poly_to_field_poly"] + drc["poly_extend_active"] + wrow_ypos = self.gnd_position.y - (k+1)*2*drc["minwidth_metal2"] + lwt_xpos = lit_xpos - (k+1)*self.w_tile_width + rot_correct + rwt_xpos = rit_xpos + w_spacer + k*self.w_tile_width + rot_correct + # add write transistors self.w_nmosL[k] = self.add_inst(name="w_nmosL{}".format(k), mod=self.w_nmos, offset=[lwt_xpos,0], rotate=90) - self.connect_inst(["IR", "WROW{}".format(k), "WBL{}".format(k), "gnd"]) + self.connect_inst(["Q", "WROW{}".format(k), "WBL{}".format(k), "gnd"]) self.w_nmosR[k] = self.add_inst(name="w_nmosR{}".format(k), mod=self.w_nmos, offset=[rwt_xpos,0], rotate=90) - self.connect_inst(["IL", "WROW{}".format(k), "WBL_bar{}".format(k), "gnd"]) - + self.connect_inst(["Q_bar", "WROW{}".format(k), "WBL_bar{}".format(k), "gnd"]) # add WROW lines self.wrow_positions[k] = vector(self.leftmost_xpos, wrow_ypos) @@ -254,130 +233,128 @@ class pbitcell(design.design): width=self.cell_width, height=drc["minwidth_metal1"]) - """ - Source/WBL/WBL_bar connections - """ - # connect sources to WBL and WBL_bar - self.wbl_positions[k] = vector(lwt_xpos - drc["minwidth_metal2"],self.botmost_ypos) + + """ Source/WBL/WBL_bar connections """ + # add contacts to connect source of wt to WBL or WBL_bar + offsetL = self.w_nmosL[k].get_pin("S").center() + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offsetL, + rotate=90) + + offsetR = self.w_nmosR[k].get_pin("S").center() + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offsetR, + rotate=90) + + # add WBL and WBL_bar (simultaneously connects to source of wt) + self.wbl_positions[k] = vector(self.w_nmosL[k].get_pin("S").center().x - 0.5*drc["minwidth_metal2"], self.botmost_ypos) self.add_layout_pin(text="WBL{}".format(k), layer="metal2", offset=self.wbl_positions[k], width=drc["minwidth_metal2"], height=self.cell_height) - self.wbl_bar_positions[k] = vector(rwt_xpos - rot_correct,self.botmost_ypos) + self.wbl_bar_positions[k] = vector(self.w_nmosR[k].get_pin("S").center().x - 0.5*drc["minwidth_metal2"], self.botmost_ypos) self.add_layout_pin(text="WBL_bar{}".format(k), layer="metal2", offset=self.wbl_bar_positions[k], width=drc["minwidth_metal2"], height=self.cell_height) - # add vias to connect source of wt to WBL and WBL_bar - offset = self.w_nmosL[k].get_pin("S").ll() + vector(self.w_nmos.active_height, 0) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) - offset = self.w_nmosR[k].get_pin("S").ll() + vector(self.w_nmos.active_height, 0) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) + """ Gate/WROW connections """ + # add contacts to connect gate of wt to WROW (poly to metal2) + offsetL = vector(self.w_nmosL[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width, self.w_nmosL[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetL) - """ - Gate/WROW connections - """ - # add vias to connect wt gate to WROW - correct = vector(0.5*(drc["minwidth_metal2"] - drc["minwidth_metal1"]),0) - offset = self.w_nmosL[k].get_pin("S").ll() - vector(drc["minwidth_metal2"] + contact.poly.width, 0) - self.add_contact(layers=("poly", "contact", "metal1"), - offset=offset) + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offsetL) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset+correct) + self.add_rect_center(layer="poly", + offset=offsetL, + width=contact.poly.width, + height=contact.poly.height) - via_offsetL = offset + vector(0.5*contact.poly.width, 0) - gate_offsetL = vector(offset.x + 0.5*contact.poly.width, self.w_nmosL[k].get_pin("G").ul().y) - self.add_path("poly", [via_offsetL, gate_offsetL], width=contact.poly.width) - self.add_path("poly", [gate_offsetL, self.w_nmosL[k].get_pin("G").lc()]) + offsetR = vector(self.w_nmosR[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width, self.w_nmosR[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetR) - offset = self.w_nmosR[k].get_pin("S").lr() + vector(drc["minwidth_metal2"], 0) - self.add_contact(layers=("poly", "contact", "metal1"), - offset=offset) + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offsetR) + + self.add_rect_center(layer="poly", + offset=offsetR, + width=contact.poly.width, + height=contact.poly.height) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset+correct) + # connect gate of wt to contact + midL = vector(offsetL.x, self.w_nmosL[k].get_pin("G").lc().y) + self.add_path("poly", [self.w_nmosL[k].get_pin("G").lc(), midL, offsetL]) - via_offsetR = offset + vector(0.5*contact.poly.width, 0) - gate_offsetR = vector(offset.x + 0.5*contact.poly.width, self.w_nmosR[k].get_pin("G").ur().y) - self.add_path("poly", [via_offsetR, gate_offsetR], width=contact.poly.width) - self.add_path("poly", [gate_offsetR, self.w_nmosR[k].get_pin("G").rc()]) + midR = vector(offsetR.x, self.w_nmosR[k].get_pin("G").rc().y) + self.add_path("poly", [self.w_nmosR[k].get_pin("G").rc(), midR, offsetR]) - # add vias to WROW lines - offset = vector(via_offsetL.x + contact.m1m2.height - 0.5*drc["minwidth_metal2"],self.wrow_positions[k].y) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) - - wrow_offset = vector(via_offsetL.x, self.wrow_positions[k].y) - self.add_path("metal2", [via_offsetL, wrow_offset]) + # add contacts to WROW lines + offset = vector(offsetL.x, self.wrow_positions[k].y + 0.5*drc["minwidth_metal1"]) + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offset, + rotate=90) - offset = vector(via_offsetR.x + 0.5*drc["minwidth_metal2"], self.wrow_positions[k].y) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) + offset = vector(offsetR.x, self.wrow_positions[k].y + 0.5*drc["minwidth_metal1"]) + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offset, + rotate=90) - wrow_offset = vector(via_offsetR.x, self.wrow_positions[k].y) - self.add_path("metal2", [via_offsetR, wrow_offset]) + # connect wt gate contacts to WROW contacts + wrow_offset = vector(offsetL.x, self.wrow_positions[k].y) + self.add_path("metal2", [offsetL, wrow_offset]) + + wrow_offset = vector(offsetR.x, self.wrow_positions[k].y) + self.add_path("metal2", [offsetR, wrow_offset]) - """ - Drain/Storage connections - """ + """ Drain/Storage connections """ if(k == self.num_write-1): - # add vias to connect input of inverters to drain of wt - offset = vector(lit_xpos - drc["minwidth_metal1"], self.i_nmos.active_height + 0.2*self.inv_gap) - self.add_contact(layers=("poly", "contact", "metal1"), - offset=offset, - rotate=90) + # add contacts to connect gate of inverters to drain of wt + offsetL = vector(self.i_nmosL.get_pin("G").lc().x - drc["poly_to_field_poly"] - 0.5*contact.poly.width, self.cross_heightL) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetL, + rotate=90) - offset = vector(rit_xpos + self.i_nmos.active_width + drc["minwidth_metal1"] + contact.poly.height, self.i_nmos.active_height + 0.2*self.inv_gap) - self.add_contact(layers=("poly", "contact", "metal1"), - offset=offset, - rotate=90) + offsetR = vector(self.i_nmosR.get_pin("G").rc().x + drc["poly_to_field_poly"] + 0.5*contact.poly.width, self.cross_heightL) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetR, + rotate=90) - # connect drains of wt to input of inverters - correct = 0.5*(contact.poly.width - drc["minwidth_metal1"]) - w_nmosL_drain = self.w_nmosL[k].get_pin("D").rc() - via_offsetLB = vector(lit_xpos - drc["minwidth_metal1"] - contact.poly.height, self.w_nmosL[k].get_pin("D").rc().y) - via_offsetLT = vector(lit_xpos - drc["minwidth_metal1"] - contact.poly.height, self.i_nmos.active_height + 0.2*self.inv_gap + contact.poly.width - correct) - self.add_path("metal1", [w_nmosL_drain, via_offsetLB, via_offsetLT]) + # connect gate of inverters to contacts + gate_offsetL = vector(self.i_nmosL.get_pin("G").lc().x, offsetL.y) + self.add_path("poly", [offsetL, gate_offsetL]) - w_nmosR_drain = self.w_nmosR[k].get_pin("D").lc() - via_offsetRB = vector(rit_xpos + self.i_nmos.active_width + drc["minwidth_metal1"] + contact.poly.height, self.w_nmosR[k].get_pin("D").lc().y) - via_offsetRT = vector(rit_xpos + self.i_nmos.active_width + drc["minwidth_metal1"] + contact.poly.height, self.i_nmos.active_height + 0.2*self.inv_gap + contact.poly.width - correct) - self.add_path("metal1", [w_nmosR_drain, via_offsetRB, via_offsetRT]) + gate_offsetR = vector(self.i_nmosR.get_pin("G").rc().x, offsetR.y) + self.add_path("poly", [offsetR, gate_offsetR]) - via_offsetL = vector(lit_xpos - drc["minwidth_metal1"] - contact.poly.height, self.i_nmos.active_height + 0.2*self.inv_gap + 0.5*contact.poly.width) - gate_offsetL = vector(self.i_nmosL.get_pin("G").ll().x, self.i_nmos.active_height + 0.2*self.inv_gap + 0.5*contact.poly.width) - self.add_path("poly", [via_offsetL, gate_offsetL], width=contact.poly.width) + # connect contacts to drains of wt + midL0 = vector(self.i_nmosL.get_pin("S").lc().x - 1.5*drc["minwidth_metal1"], offsetL.y) + midL1 = vector(self.i_nmosL.get_pin("S").lc().x - 1.5*drc["minwidth_metal1"], self.w_nmosL[k].get_pin("D").lc().y) + self.add_path("metal1", [offsetL, midL0, midL1, self.w_nmosL[k].get_pin("D").lc()]) - via_offsetR = vector(rit_xpos + self.i_nmos.active_width + drc["minwidth_metal1"] + contact.poly.height, self.i_nmos.active_height + 0.2*self.inv_gap + 0.5*contact.poly.width) - gate_offsetR = vector(self.i_nmosR.get_pin("G").lr().x, self.i_nmos.active_height + 0.2*self.inv_gap + 0.5*contact.poly.width) - self.add_path("poly", [via_offsetR, gate_offsetR], width=contact.poly.width) + midR0 = vector(self.i_nmosR.get_pin("D").rc().x + 1.5*drc["minwidth_metal1"], offsetR.y) + midR1 = vector(self.i_nmosR.get_pin("D").rc().x + 1.5*drc["minwidth_metal1"], self.w_nmosR[k].get_pin("D").rc().y) + self.add_path("metal1", [offsetR, midR0, midR1, self.w_nmosR[k].get_pin("D").rc()]) def add_read_transistors(self): - """ - Define variables relevant to read transistors - """ + """ Define variables relevant to read transistors """ lit_xpos = -(self.i_nmos.active_width + 1.5*parameter["min_tx_size"]) - rit_xpos = 1.5*parameter["min_tx_size"] - wrow_ypos = -2*drc["minwidth_metal1"] - self.num_write*2*drc["minwidth_metal2"] + rit_xpos = 1.5*parameter["min_tx_size"] + self.i_nmos.active_width lwt_xpos = lit_xpos - self.num_write*self.w_tile_width - rwt_xpos = rit_xpos + self.i_nmos.active_width + self.num_write*self.w_tile_width + rwt_xpos = rit_xpos + self.num_write*self.w_tile_width + wrow_ypos = self.gnd_position.y - self.num_write*2*drc["minwidth_metal2"] rot_correct = self.r_nmos.active_height - spacer = 5*drc["minwidth_metal2"] + r_spacer = 2*drc["minwidth_poly"] + drc["minwidth_metal1"] + 2*contact.poly.width + rw_spacer = drc["minwidth_poly"] + drc["poly_to_field_poly"] + drc["minwidth_metal2"] + 2*contact.poly.width + self.w_ex self.r_nmosL = [None] * self.num_read self.r_nmosR = [None] * self.num_read @@ -387,24 +364,23 @@ class pbitcell(design.design): for k in range(0,self.num_read): - """ - Add transistors and RROW lines - """ - lrt_xpos = lwt_xpos - spacer - self.r_nmos.active_height + rot_correct - k*self.r_tile_width - rrt_xpos = rwt_xpos + spacer + rot_correct + k*self.r_tile_width + """ Add transistors and RROW lines """ + # calculate transistor offsets + lrt_xpos = lwt_xpos - rw_spacer - self.r_nmos.active_height - k*self.r_tile_width + rot_correct + rrt_xpos = rwt_xpos + rw_spacer + k*self.r_tile_width + rot_correct + # add read transistors self.r_nmosL[k] = self.add_inst(name="r_nmosL", mod=self.r_nmos, offset=[lrt_xpos,0], rotate=90) - self.connect_inst(["RROW{}".format(k), "IL", "RBL{}".format(k), "gnd"]) + self.connect_inst(["RROW{}".format(k), "Q", "RBL{}".format(k), "gnd"]) self.r_nmosR[k] = self.add_inst(name="r_nmosR", mod=self.r_nmos, offset=[rrt_xpos,0], rotate=90) - self.connect_inst(["RROW{}".format(k), "IR", "RBL_bar{}".format(k), "gnd"]) - + self.connect_inst(["RROW{}".format(k), "Q_bar", "RBL_bar{}".format(k), "gnd"]) # add RROW lines rrow_ypos = wrow_ypos - (k+1)*2*drc["minwidth_metal2"] @@ -414,133 +390,200 @@ class pbitcell(design.design): offset=self.rrow_positions[k], width=self.cell_width, height=drc["minwidth_metal1"]) - - """ - Drain/RBL/RBL_bar connections - """ - # connect drains to RBL and RBL_bar - self.rbl_positions[k] = vector(self.r_nmosL[k].get_pin("D").rc().x + drc["minwidth_metal2"],self.botmost_ypos) + + + """ Source of RA transistor / GND connection """ + offset = vector(self.r_nmosL[k].get_pins("S")[0].bc().x, self.gnd_position.y) + self.add_path("metal1", [self.r_nmosL[k].get_pins("S")[0].bc(), offset]) + + offset = vector(self.r_nmosR[k].get_pins("S")[0].bc().x, self.gnd_position.y) + self.add_path("metal1", [self.r_nmosR[k].get_pins("S")[0].bc(), offset]) + + + """ Source of R transistor / RBL & RBL_bar connection """ + # add contacts to connect source of rt to RBL or RBL_bar + offsetL = self.r_nmosL[k].get_pins("S")[1].center() + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offsetL, + rotate=90) + + offsetR = self.r_nmosR[k].get_pins("S")[1].center() + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offsetR, + rotate=90) + + # add RBL and RBL_bar (simultaneously connects to source of rt) + self.rbl_positions[k] = vector(self.r_nmosL[k].get_pins("S")[1].center().x - 0.5*drc["minwidth_metal2"], self.botmost_ypos) self.add_layout_pin(text="RBL{}".format(k), layer="metal2", offset=self.rbl_positions[k], width=drc["minwidth_metal2"], height=self.cell_height) - self.rbl_bar_positions[k] = vector(self.r_nmosR[k].get_pin("D").lc().x - 2*drc["minwidth_metal2"],self.botmost_ypos) + self.rbl_bar_positions[k] = vector(self.r_nmosR[k].get_pins("S")[1].center().x - 0.5*drc["minwidth_metal2"], self.botmost_ypos) self.add_layout_pin(text="RBL_bar{}".format(k), layer="metal2", offset=self.rbl_bar_positions[k], width=drc["minwidth_metal2"], height=self.cell_height) - # add vias to connect drain of rt to RBL and RBL_bar - offset = self.r_nmosL[k].get_pin("D").ll() + vector(contact.m1m2.height, 0) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) - offset = self.r_nmosR[k].get_pin("D").ll() + vector(contact.m1m2.height, 0) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) - - # connect drain of rt to RBL and RBL_bar - rbl_offset = vector(self.rbl_positions[k].x, self.r_nmosL[k].get_pin("D").lc().y) - self.add_path("metal2", [self.r_nmosL[k].get_pin("D").lc(), rbl_offset]) + """ Gate of R transistor / RROW connection """ + # add contact to connect gate of rt to RROW (poly to metal2) + offsetL = vector(lrt_xpos - rot_correct - drc["minwidth_poly"] - 0.5*contact.poly.width, self.r_nmosL[k].get_pins("G")[1].lc().y) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetL) + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offsetL) + + offsetR = vector(rrt_xpos + drc["minwidth_poly"] + 0.5*contact.poly.width, self.r_nmosR[k].get_pins("G")[1].rc().y) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetR) + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=offsetR) - rbl_bar_offset = vector(self.rbl_bar_positions[k].x, self.r_nmosR[k].get_pin("D").rc().y) - self.add_path("metal2", [self.r_nmosR[k].get_pin("D").rc(), rbl_bar_offset]) - - """ - Source/RROW connections - """ - # add vias on rt sources - offset = self.r_nmosL[k].get_pin("S").ll() + vector(contact.m1m2.height, 0) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) + # connect gate of rt to contact + self.add_path("poly", [self.r_nmosL[k].get_pins("G")[1].lc(), offsetL]) + self.add_path("poly", [self.r_nmosR[k].get_pins("G")[1].rc(), offsetR]) - offset = self.r_nmosR[k].get_pin("S").ll() + vector(contact.m1m2.height, 0) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) + # add contacts to RROW lines + row_offsetL = vector(self.r_nmosL[k].get_pins("S")[1].lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width, self.rrow_positions[k].y + 0.5*drc["minwidth_metal1"]) + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=row_offsetL, + rotate=90) + + row_offsetR = vector(self.r_nmosR[k].get_pins("S")[1].rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width, self.rrow_positions[k].y + 0.5*drc["minwidth_metal1"]) + self.add_contact_center(layers=("metal1", "via1", "metal2"), + offset=row_offsetR, + rotate=90) - # add vias on rrows - offset = vector(self.r_nmosL[k].get_pin("S").ll().x + contact.m1m2.height, self.rrow_positions[k].y) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) + # connect rt gate contacts to RROW contacts + self.add_path("metal2", [offsetL, row_offsetL]) + self.add_path("metal2", [offsetR, row_offsetR]) - offset = vector(self.r_nmosR[k].get_pin("S").ll().x + contact.m1m2.height, self.rrow_positions[k].y) - self.add_contact(layers=("metal1", "via1", "metal2"), - offset=offset, - rotate=90) - # connect sources of rt to rrows - rrow_offset = vector(self.r_nmosL[k].get_pin("S").bc().x, self.rrow_positions[k].y) - self.add_path("metal2", [self.r_nmosL[k].get_pin("S").bc(), rrow_offset]) + """ Gate of RA transistor / storage connection """ + # add contact to connect gate of rat to output of inverters + offsetL = vector(lrt_xpos + drc["minwidth_poly"] + 0.5*contact.poly.width, self.r_nmosL[k].get_pins("G")[0].rc().y) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetL) + + offsetR = vector(rrt_xpos - rot_correct - drc["minwidth_poly"] - 0.5*contact.poly.width, self.r_nmosR[k].get_pins("G")[0].lc().y) + self.add_contact_center(layers=("poly", "contact", "metal1"), + offset=offsetR) - rrow_offset = vector(self.r_nmosR[k].get_pin("S").bc().x, self.rrow_positions[k].y) - self.add_path("metal2", [self.r_nmosR[k].get_pin("S").bc(), rrow_offset]) + # connect gate of rat to contact + self.add_path("poly", [self.r_nmosL[k].get_pins("G")[0].rc(), offsetL]) + self.add_path("poly", [self.r_nmosR[k].get_pins("G")[0].lc(), offsetR]) - """ - Gate/inverter connections - """ - # add vias to connect to gate of rt - offsetL = vector(self.r_nmosL[k].get_pin("D").lr().x + drc["minwidth_metal1"], self.r_nmosL[k].get_pin("G").lr().y) - self.add_contact(layers=("poly", "contact", "metal1"), - offset=offsetL) - - offsetR = vector(self.r_nmosR[k].get_pin("D").ll().x - drc["minwidth_metal1"] - contact.poly.width, self.r_nmosR[k].get_pin("G").ll().y) - self.add_contact(layers=("poly", "contact", "metal1"), - offset=offsetR) - - # add metal1 path between gate vias and inverter inputs - midL = vector(offsetL.x + 0.5*contact.poly.width, self.i_nmos.active_height + 0.6*self.inv_gap + 0.5*drc["minwidth_metal1"]) - gate_offsetL = vector(self.i_nmosL.get_pin("D").ll().x, self.i_nmos.active_height + 0.6*self.inv_gap + 0.5*drc["minwidth_metal1"]) - self.add_path("metal1", [offsetL+vector(0.5*contact.poly.width,0), midL, gate_offsetL]) - - midR = vector(offsetR.x + 0.5*contact.poly.width, self.i_nmos.active_height + 0.6*self.inv_gap + 0.5*drc["minwidth_metal1"]) - gate_offsetR = vector(self.i_nmosR.get_pin("S").lr().x, self.i_nmos.active_height + 0.6*self.inv_gap + 0.5*drc["minwidth_metal1"]) - self.add_path("metal1", [offsetR+vector(0.5*contact.poly.width,0), midR, gate_offsetR]) + # connect contact to output of inverters + midL0 = vector(offsetL.x, self.r_nmosL[k].get_pins("S")[1].uc().y + 1.5*drc["minwidth_metal1"]) + midL1 = vector(self.i_nmosL.get_pin("S").lc().x - 1.5*drc["minwidth_metal1"], self.r_nmosL[0].get_pins("S")[1].uc().y + 1.5*drc["minwidth_metal1"]) + midL2 = vector(self.i_nmosL.get_pin("S").lc().x - 1.5*drc["minwidth_metal1"], self.cross_heightU) + gate_offsetL = vector(self.i_nmosL.get_pin("D").center().x, self.cross_heightU) + self.add_path("metal1", [offsetL, midL0, midL1, midL2, gate_offsetL]) + midR0 = vector(offsetR.x, self.r_nmosR[k].get_pins("S")[1].uc().y + 1.5*drc["minwidth_metal1"]) + midR1 = vector(self.i_nmosR.get_pin("D").rc().x + 1.5*drc["minwidth_metal1"], self.r_nmosR[k].get_pins("S")[1].uc().y + 1.5*drc["minwidth_metal1"]) + midR2 = vector(self.i_nmosR.get_pin("D").rc().x + 1.5*drc["minwidth_metal1"], self.cross_heightU) + gate_offsetR = vector(self.i_nmosR.get_pin("S").center().x, self.cross_heightU) + self.add_path("metal1", [offsetR, midR0, midR1, midR2, gate_offsetR]) def extend_well(self): - offset = vector(self.leftmost_xpos, -2*drc["minwidth_metal1"]) - well_height = self.w_nmos.well_width + 2*drc["minwidth_metal1"] + """ extend nwell and pwell """ + # extend pwell to encompass i_nmos + offset = vector(self.leftmost_xpos, self.botmost_ypos) + well_height = -self.botmost_ypos + self.i_nmos.well_height - drc["well_enclosure_active"] self.add_rect(layer="pwell", offset=offset, width=self.cell_width, height=well_height) + + # extend pwell to encompass r_nmos + r_well_width = self.num_read*self.r_tile_width + r_well_height = self.r_nmos.well_width - drc["well_enclosure_active"] + offset = vector(self.leftmost_xpos, 0) + self.add_rect(layer="pwell", + offset=offset, + width=r_well_width, + height=r_well_height) + + offset = vector(-self.leftmost_xpos - r_well_width, 0) + self.add_rect(layer="pwell", + offset=offset, + width=r_well_width, + height=r_well_height) + + # extend pwell to encompass w_nmos + lwt_xpos = -(self.i_nmos.active_width + 1.5*parameter["min_tx_size"] + self.w_tile_width - self.w_nmos.active_height - drc["well_enclosure_active"]) + rwt_xpos = 1.5*parameter["min_tx_size"] + self.i_nmos.active_width + self.w_tile_width - self.w_nmos.active_height - drc["well_enclosure_active"] + w_well_width = -(self.leftmost_xpos - lwt_xpos) + w_well_height = self.w_nmos.well_width - drc["well_enclosure_active"] + offset = vector(lwt_xpos - w_well_width, 0) + self.add_rect(layer="pwell", + offset=offset, + width=w_well_width, + height=w_well_height) + + offset = vector(rwt_xpos, 0) + self.add_rect(layer="pwell", + offset=offset, + width=w_well_width, + height=w_well_height) + + # extend nwell to encompass i_pmos lit_xpos = -(self.i_nmos.active_width + 1.5*parameter["min_tx_size"] + drc["well_enclosure_active"]) it_ypos = self.inv_gap + self.i_nmos.active_height - drc["well_enclosure_active"] offset = [lit_xpos,it_ypos] well_width = 2*self.i_pmos.active_width + 3*parameter["min_tx_size"] + 2*drc["well_enclosure_active"] - well_height = self.i_pmos.well_height + 2*drc["minwidth_metal1"] + well_height = self.vdd_position.y - it_ypos + drc["well_enclosure_active"] + drc["minwidth_tx"] self.add_rect(layer="nwell", offset=offset, width=well_width, height=well_height) + """ add well contacts """ + # connect pimplants to gnd + offset = vector(0, self.gnd_position.y + 0.5*drc["minwidth_metal1"]) + self.add_contact_center(layers=("active", "contact", "metal1"), + offset=offset, + rotate=90) + + self.add_rect_center(layer="pimplant", + offset=offset, + width=drc["minwidth_tx"], + height=drc["minwidth_tx"]) + + # connect nimplants to vdd + offset = vector(0, self.vdd_position.y + 0.5*drc["minwidth_metal1"]) + self.add_contact_center(layers=("active", "contact", "metal1"), + offset=offset, + rotate=90) + + self.add_rect_center(layer="nimplant", + offset=offset, + width=drc["minwidth_tx"], + height=drc["minwidth_tx"]) + def add_fail(self): # for failing drc - frail_width = self.well_width = 10*drc["minwidth_tx"] + frail_width = self.well_width = 2*drc["minwidth_metal1"] frail_height = self.rail_height = drc["minwidth_metal1"] - self.gnd_position = vector(-25*drc["minwidth_tx"], - 1.5 * drc["minwidth_metal1"] - 0.5 * frail_height) # for tiling purposes + fail_position = vector(-25*drc["minwidth_tx"], - 1.5 * drc["minwidth_metal1"] - 0.5 * frail_height) # for tiling purposes self.add_layout_pin(text="gnd", layer="metal1", - offset=self.gnd_position, + offset=fail_position, width=frail_width, height=frail_height) - self.gnd_position2 = vector(-25*drc["minwidth_tx"], - 0.5 * drc["minwidth_metal1"]) + fail_position2 = vector(-25*drc["minwidth_tx"], - 0.5 * drc["minwidth_metal1"]) self.add_layout_pin(text="gnd2", layer="metal1", - offset=self.gnd_position2, + offset=fail_position2, width=frail_width, height=frail_height) diff --git a/compiler/tests/04_pbitcell_0R_test.py b/compiler/tests/04_pbitcell_0R_test.py new file mode 100644 index 00000000..9766db8a --- /dev/null +++ b/compiler/tests/04_pbitcell_0R_test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python2.7 +""" +Run regresion tests on a parameterized inverter +""" + +import unittest +from testutils import header +import sys,os +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +import debug +import verify + +OPTS = globals.OPTS + +#@unittest.skip("SKIPPING 04_pbitcell_test") + + +class pbitcell_test(unittest.TestCase): + + def runTest(self): + globals.init_openram("config_20_{0}".format(OPTS.tech_name)) + OPTS.check_lvsdrc = False + + import pbitcell + import tech + + debug.info(2, "Test for pbitcell with 2 write ports and 0 read ports") + tx = pbitcell.pbitcell(num_write=2,num_read=0) + self.local_check(tx) + + OPTS.check_lvsdrc = True + globals.end_openram() + + def local_check(self, tx): + tempspice = OPTS.openram_temp + "temp.sp" + tempgds = OPTS.openram_temp + "temp.gds" + + tx.sp_write(tempspice) + tx.gds_write(tempgds) + + self.assertFalse(verify.run_drc(tx.name, tempgds)) + self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice)) + + os.remove(tempspice) + os.remove(tempgds) + + # reset the static duplicate name checker for unit tests + import design + design.design.name_map=[] + + + + +# instantiate a copy of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/compiler/tests/04_pbitcell_0W_test.py b/compiler/tests/04_pbitcell_0W_test.py new file mode 100644 index 00000000..38b1dd25 --- /dev/null +++ b/compiler/tests/04_pbitcell_0W_test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python2.7 +""" +Run regresion tests on a parameterized inverter +""" + +import unittest +from testutils import header +import sys,os +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +import debug +import verify + +OPTS = globals.OPTS + +#@unittest.skip("SKIPPING 04_pbitcell_test") + + +class pbitcell_test(unittest.TestCase): + + def runTest(self): + globals.init_openram("config_20_{0}".format(OPTS.tech_name)) + OPTS.check_lvsdrc = False + + import pbitcell + import tech + + debug.info(2, "Test for pbitcell with 0 write ports and 2 read ports") + tx = pbitcell.pbitcell(num_write=0,num_read=2) + self.local_check(tx) + + OPTS.check_lvsdrc = True + globals.end_openram() + + def local_check(self, tx): + tempspice = OPTS.openram_temp + "temp.sp" + tempgds = OPTS.openram_temp + "temp.gds" + + tx.sp_write(tempspice) + tx.gds_write(tempgds) + + self.assertFalse(verify.run_drc(tx.name, tempgds)) + self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice)) + + os.remove(tempspice) + os.remove(tempgds) + + # reset the static duplicate name checker for unit tests + import design + design.design.name_map=[] + + + + +# instantiate a copy of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index e5512a1c..3ba42b76 100644 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -25,8 +25,8 @@ class pbitcell_test(unittest.TestCase): import pbitcell import tech - debug.info(2, "Test for pbitcell") - tx = pbitcell.pbitcell() + debug.info(2, "Test for pbitcell with 2 write ports and 2 read ports") + tx = pbitcell.pbitcell(num_write=2,num_read=2) self.local_check(tx) OPTS.check_lvsdrc = True