fixed bitcell_array to work with different sized pbitcells, changed sizing in pbitcell to minimize space between inverters

This commit is contained in:
Michael Timothy Grimes 2018-03-08 16:39:26 -08:00
parent 0ea5d0b6a7
commit 65735c08e2
3 changed files with 51 additions and 42 deletions

View File

@ -88,18 +88,26 @@ class bitcell_array(design.design):
dir_key = ""
if(OPTS.bitcell == "pbitcell"):
bitcell_nets = []
for k in range(self.num_write):
bitcell_nets.append("wbl{0}[{1}]".format(k,col))
bitcell_nets.append("wbl_bar{0}[{1}]".format(k,col))
for k in range(self.num_read):
bitcell_nets.append("rbl{0}[{1}]".format(k,col))
bitcell_nets.append("rbl_bar{0}[{1}]".format(k,col))
for k in range(self.num_write):
bitcell_nets.append("wrow{0}[{1}]".format(k,row))
for k in range(self.num_read):
bitcell_nets.append("rrow{0}[{1}]".format(k,row))
bitcell_nets.append("vdd")
bitcell_nets.append("gnd")
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.cell,
offset=[xoffset, tempy],
mirror=dir_key)
self.connect_inst(["wbl0[{0}]".format(col),
"wbl_bar0[{0}]".format(col),
"rbl0[{0}]".format(col),
"rbl_bar0[{0}]".format(col),
"wrow0[{0}]".format(row),
"rrow0[{0}]".format(row),
"vdd",
"gnd"])
self.connect_inst(bitcell_nets)
else:
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.cell,

View File

@ -101,20 +101,20 @@ class pbitcell(pgate.pgate):
self.write_nmos_contact_extension = 0.5*(self.write_nmos.active_contact.height - self.write_nmos.active_height)
# calculation for transistor spacing (exact solutions)
#self.inverter_to_inverter_spacing = 3*parameter["min_tx_size"]
#self.inverter_to_write_spacing = need to calculate
#self.write_to_write_spacing = drc["minwidth_metal2"] + self.write_nmos_contact_extension + contact.poly.width + drc["poly_to_field_poly"] + drc["poly_extend_active"]
#self.write_to_read_spacing = drc["minwidth_poly"] + drc["poly_to_field_poly"] + drc["minwidth_metal2"] + 2*contact.poly.width + self.write_nmos_contact_extension
#self.read_to_read_spacing = 2*drc["minwidth_poly"] + drc["minwidth_metal1"] + 2*contact.poly.width
self.inverter_to_inverter_spacing = contact.poly.height + drc["minwidth_metal1"]
self.inverter_to_write_spacing = drc["pwell_to_nwell"] + 2*drc["well_enclosure_active"]
self.write_to_write_spacing = drc["minwidth_metal2"] + self.write_nmos_contact_extension + contact.poly.width + drc["poly_to_field_poly"] + drc["poly_extend_active"]
self.write_to_read_spacing = drc["minwidth_poly"] + drc["poly_to_field_poly"] + drc["minwidth_metal2"] + 2*contact.poly.width + self.write_nmos_contact_extension
self.read_to_read_spacing = 2*drc["minwidth_poly"] + drc["minwidth_metal1"] + 2*contact.poly.width
# calculation for transistor spacing (symmetric solutions)
self.inverter_to_inverter_spacing = 3*parameter["min_tx_size"]
#self.inverter_to_inverter_spacing = 3*parameter["min_tx_size"]
#self.inverter_to_write_spacing = need to calculate
spacing_option1 = contact.poly.width + 2*drc["poly_to_field_poly"] + 2*drc["poly_extend_active"]
spacing_option2 = contact.poly.width + 2*drc["minwidth_metal2"] + 2*self.write_nmos_contact_extension
self.write_to_write_spacing = max(spacing_option1, spacing_option2)
self.write_to_read_spacing = drc["poly_to_field_poly"] + 2*contact.poly.width + 2*drc["minwidth_metal2"] + 2*self.write_nmos_contact_extension
self.read_to_read_spacing = drc["minwidth_metal1"] + 2*contact.poly.width + 2*drc["minwidth_poly"]
#spacing_option1 = contact.poly.width + 2*drc["poly_to_field_poly"] + 2*drc["poly_extend_active"]
#spacing_option2 = contact.poly.width + 2*drc["minwidth_metal2"] + 2*self.write_nmos_contact_extension
#self.write_to_write_spacing = max(spacing_option1, spacing_option2)
#self.write_to_read_spacing = drc["poly_to_field_poly"] + 2*contact.poly.width + 2*drc["minwidth_metal2"] + 2*self.write_nmos_contact_extension
#self.read_to_read_spacing = drc["minwidth_metal1"] + 2*contact.poly.width + 2*drc["minwidth_poly"]
# calculations for transistor tiling (includes transistor and spacing)
self.inverter_tile_width = self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing
@ -122,6 +122,7 @@ class pbitcell(pgate.pgate):
self.read_tile_width = self.read_to_read_spacing + self.read_nmos.active_height
# calculation for row line tiling
self.rail_tile_height = drc["active_to_body_active"] + 0.5*(drc["minwidth_tx"] - drc["minwidth_metal1"]) + drc["minwidth_metal1"]
self.rowline_tile_height = drc["minwidth_metal1"] + contact.m1m2.width
# calculations related to inverter connections
@ -138,7 +139,7 @@ class pbitcell(pgate.pgate):
# leftmost position = storage width + write ports width + read ports width + read transistor gate connections + metal spacing necessary for tiling the bitcell
self.leftmost_xpos = -self.inverter_tile_width \
- self.num_write*self.write_tile_width \
- self.inverter_to_write_spacing - self.write_nmos.active_height - (self.num_write-1)*self.write_tile_width \
- read_port_flag*(self.write_to_read_spacing + self.read_nmos.active_height + (self.num_read-1)*self.read_tile_width) \
- drc["minwidth_poly"] - contact.m1m2.height \
- 0.5*drc["minwidth_metal2"]
@ -146,13 +147,13 @@ class pbitcell(pgate.pgate):
self.rightmost_xpos = -self.leftmost_xpos
# bottommost position = gnd height + wrow height + rrow height
self.botmost_ypos = -self.rowline_tile_height \
self.botmost_ypos = -self.rail_tile_height \
- self.num_write*self.rowline_tile_height \
- read_port_flag*(self.num_read*self.rowline_tile_height)
# topmost position = height of the inverter + height of vdd
self.topmost_ypos = self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height \
+ self.inverter_pmos_contact_extension + 2*drc["minwidth_metal1"]
+ self.rail_tile_height
# calculations for the cell dimensions
self.width = -2*self.leftmost_xpos
@ -225,14 +226,17 @@ class pbitcell(pgate.pgate):
"""
""" Add rails for vdd and gnd """
self.gnd_position = vector(self.leftmost_xpos, -self.rowline_tile_height)
self.gnd_position = vector(self.leftmost_xpos, -self.rail_tile_height)
self.gnd = self.add_layout_pin(text="gnd",
layer="metal1",
offset=self.gnd_position,
width=self.width,
height=contact.well.second_layer_width)
self.vdd_position = vector(self.leftmost_xpos, self.inverter_pmos_left.get_pin("S").uc().y + drc["minwidth_metal1"])
vdd_ypos = self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height \
+ drc["active_to_body_active"] + 0.5*(drc["minwidth_tx"] - drc["minwidth_metal1"])
#vdd_ypos = self.inverter_pmos_left.get_pin("S").uc().y + drc["minwidth_metal1"]
self.vdd_position = vector(self.leftmost_xpos, vdd_ypos)
self.vdd = self.add_layout_pin(text="vdd",
layer="metal1",
offset=self.vdd_position,
@ -280,11 +284,11 @@ class pbitcell(pgate.pgate):
""" Add transistors """
# calculate write transistor offsets
left_write_transistor_xpos = -self.inverter_tile_width \
- (k+1)*self.write_tile_width \
- self.inverter_to_write_spacing - self.write_nmos.active_height - k*self.write_tile_width \
+ write_rotation_correct
right_write_transistor_xpos = self.inverter_tile_width \
+ self.write_to_write_spacing + k*self.write_tile_width \
+ self.inverter_to_write_spacing + k*self.write_tile_width \
+ write_rotation_correct
# add write transistors
@ -446,12 +450,12 @@ class pbitcell(pgate.pgate):
""" Add transistors """
# calculate transistor offsets
left_read_transistor_xpos = -self.inverter_tile_width \
- self.num_write*self.write_tile_width \
- self.inverter_to_write_spacing - self.write_nmos.active_height - (self.num_write-1)*self.write_tile_width \
- self.write_to_read_spacing - self.read_nmos.active_height - k*self.read_tile_width \
+ read_rotation_correct
right_read_transistor_xpos = self.inverter_tile_width \
+ self.num_write*self.write_tile_width \
+ self.inverter_to_write_spacing + self.write_nmos.active_height + (self.num_write-1)*self.write_tile_width \
+ self.write_to_read_spacing + k*self.read_tile_width \
+ read_rotation_correct
@ -708,20 +712,17 @@ class pbitcell(pgate.pgate):
def add_fail(self):
# for failing drc when I want to observe the gds layout
frail_width = self.well_width = 2*drc["minwidth_metal1"]
frail_height = self.rail_height = drc["minwidth_metal1"]
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",
# for failing drc when I want to observe the gds layout
fail_position = vector(-4*drc["minwidth_metal1"], 0) # for tiling purposes
self.add_layout_pin(text="fail1",
layer="metal1",
offset=fail_position,
width=frail_width,
height=frail_height)
width=drc["minwidth_metal1"],
height=drc["minwidth_metal1"])
fail_position2 = vector(-25*drc["minwidth_tx"], - 0.5 * drc["minwidth_metal1"])
self.add_layout_pin(text="gnd2",
fail_position2 = vector(-4*drc["minwidth_metal1"], -1.5*drc["minwidth_metal1"])
self.add_layout_pin(text="fail2",
layer="metal1",
offset=fail_position2,
width=frail_width,
height=frail_height)
width=drc["minwidth_metal1"],
height=drc["minwidth_metal1"])

View File

@ -11,9 +11,9 @@ import globals
from globals import OPTS
import debug
#@unittest.skip("SKIPPING 05_array_test")
#@unittest.skip("SKIPPING 05_array_multiport_test")
class array_test(openram_test):
class array_multiport_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))