Added member functions to bitcell.py and pbitcell.py for use in bitcell_array.py. bitcell_array now used only one function for every type of bitcell.

This commit is contained in:
Michael Timothy Grimes 2018-03-15 12:02:38 -07:00
parent 65735c08e2
commit 0cc077598e
3 changed files with 110 additions and 204 deletions

View File

@ -34,3 +34,26 @@ class bitcell(design.design):
c_para = spice["min_tx_drain_c"] c_para = spice["min_tx_drain_c"]
result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = swing) result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = swing)
return result return result
def list_bitcell_pins(self, col, row):
# Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array
bitcell_pins = ["bl[{0}]".format(col),
"br[{0}]".format(col),
"wl[{0}]".format(row),
"vdd",
"gnd"]
return bitcell_pins
def list_row_pins(self):
# Creates a list of row pins
row_pins = ["WL"]
return row_pins
def list_column_pins(self):
# Creates a list of column pins
column_pins = ["BL", "BR"]
return column_pins

View File

@ -30,47 +30,25 @@ class bitcell_array(design.design):
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] self.height = self.row_size*self.cell.height + drc["well_enclosure_active"]
self.width = self.column_size*self.cell.width self.width = self.column_size*self.cell.width
if(OPTS.bitcell == "pbitcell"): self.add_pins()
self.add_multiport_pins()
else:
self.add_pins()
self.create_layout() self.create_layout()
self.add_layout_pins()
if(OPTS.bitcell == "pbitcell"):
self.add_multiport_layout_pins()
else:
self.add_layout_pins()
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
row_list = self.cell.list_row_pins()
column_list = self.cell.list_column_pins()
for col in range(self.column_size): for col in range(self.column_size):
self.add_pin("bl[{0}]".format(col)) for cell_column in column_list:
self.add_pin("br[{0}]".format(col)) self.add_pin(cell_column+"[{0}]".format(col))
for row in range(self.row_size): for row in range(self.row_size):
self.add_pin("wl[{0}]".format(row)) for cell_row in row_list:
self.add_pin(cell_row+"[{0}]".format(row))
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
def add_multiport_pins(self):
self.num_write = self.cell.num_write
self.num_read = self.cell.num_read
for col in range(self.column_size):
for k in range(self.num_write):
self.add_pin("wbl{0}[{1}]".format(k,col))
self.add_pin("wbl_bar{0}[{1}]".format(k,col))
for k in range(self.num_read):
self.add_pin("rbl{0}[{1}]".format(k,col))
self.add_pin("rbl_bar{0}[{1}]".format(k,col))
for row in range(self.row_size):
for k in range(self.num_write):
self.add_pin("wrow{0}[{1}]".format(k,row))
for k in range(self.num_read):
self.add_pin("rrow{0}[{1}]".format(k,row))
self.add_pin("vdd")
self.add_pin("gnd")
def create_layout(self): def create_layout(self):
xoffset = 0.0 xoffset = 0.0
@ -87,37 +65,11 @@ class bitcell_array(design.design):
tempy = yoffset tempy = yoffset
dir_key = "" dir_key = ""
if(OPTS.bitcell == "pbitcell"): self.cell_inst[row,col]=self.add_inst(name=name,
bitcell_nets = [] mod=self.cell,
for k in range(self.num_write): offset=[xoffset, tempy],
bitcell_nets.append("wbl{0}[{1}]".format(k,col)) mirror=dir_key)
bitcell_nets.append("wbl_bar{0}[{1}]".format(k,col)) self.connect_inst(self.cell.list_bitcell_pins(col, row))
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(bitcell_nets)
else:
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.cell,
offset=[xoffset, tempy],
mirror=dir_key)
self.connect_inst(["bl[{0}]".format(col),
"br[{0}]".format(col),
"wl[{0}]".format(row),
"vdd",
"gnd"])
yoffset += self.cell.height yoffset += self.cell.height
xoffset += self.cell.width xoffset += self.cell.width
@ -147,124 +99,18 @@ class bitcell_array(design.design):
# overlapping cells # overlapping cells
full_width = self.width - 2*lower_x full_width = self.width - 2*lower_x
offset = vector(0.0, 0.0) row_list = self.cell.list_row_pins()
for col in range(self.column_size): column_list = self.cell.list_column_pins()
# get the pin of the lower row cell and make it the full width
bl_pin = self.cell_inst[0,col].get_pin("BL")
br_pin = self.cell_inst[0,col].get_pin("BR")
self.add_layout_pin(text="bl[{0}]".format(col),
layer="metal2",
offset=bl_pin.ll(),
width=bl_pin.width(),
height=full_height)
self.add_layout_pin(text="br[{0}]".format(col),
layer="metal2",
offset=br_pin.ll(),
width=br_pin.width(),
height=full_height)
# gnd offset is 0 in our cell, but it be non-zero
gnd_pins = self.cell_inst[0,col].get_pins("gnd")
for gnd_pin in gnd_pins:
# avoid duplicates by only doing even rows
# also skip if it isn't the pin that spans the entire cell down to the bottom
if gnd_pin.layer=="metal2" and gnd_pin.by()==lower_y:
self.add_layout_pin(text="gnd",
layer="metal2",
offset=gnd_pin.ll(),
width=gnd_pin.width(),
height=full_height)
# increments to the next column width
offset.x += self.cell.width
offset.x = 0.0
for row in range(self.row_size):
wl_pin = self.cell_inst[row,0].get_pin("WL")
vdd_pins = self.cell_inst[row,0].get_pins("vdd")
gnd_pins = self.cell_inst[row,0].get_pins("gnd")
for gnd_pin in gnd_pins:
if gnd_pin.layer=="metal1":
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll(),
width=full_width,
height=drc["minwidth_metal1"])
# add vdd label and offset
# only add to even rows to avoid duplicates
for vdd_pin in vdd_pins:
if row % 2 == 0 and vdd_pin.layer=="metal1":
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll(),
width=full_width,
height=drc["minwidth_metal1"])
# add wl label and offset
self.add_layout_pin(text="wl[{0}]".format(row),
layer="metal1",
offset=wl_pin.ll(),
width=full_width,
height=wl_pin.height())
# increments to the next row height
offset.y += self.cell.height
def add_multiport_layout_pins(self):
# Our cells have multiple gnd pins for now.
# FIXME: fix for multiple vdd too
vdd_pin = self.cell.get_pin("vdd")
# shift it up by the overlap amount (gnd_pin) too
# must find the lower gnd pin to determine this overlap
lower_y = self.cell.height
gnd_pins = self.cell.get_pins("gnd")
for gnd_pin in gnd_pins:
if gnd_pin.layer=="metal2" and gnd_pin.by()<lower_y:
lower_y=gnd_pin.by()
# lower_y is negative, so subtract off double this amount for each pair of
# overlapping cells
full_height = self.height - 2*lower_y
vdd_pin = self.cell.get_pin("vdd")
lower_x = vdd_pin.lx()
# lower_x is negative, so subtract off double this amount for each pair of
# overlapping cells
full_width = self.width - 2*lower_x
offset = vector(0.0, 0.0) offset = vector(0.0, 0.0)
for col in range(self.column_size): for col in range(self.column_size):
# get the pin of the lower row cell and make it the full width # get the pins of the lower row cell and make it the full width
for k in range(self.num_write): for cell_column in column_list:
wbl_pin = self.cell_inst[0,col].get_pin("wbl{0}".format(k)) bl_pin = self.cell_inst[0,col].get_pin(cell_column)
self.add_layout_pin(text="wbl{0}[{1}]".format(k,col), self.add_layout_pin(text=cell_column+"[{0}]".format(col),
layer="metal2", layer="metal2",
offset=wbl_pin.ll(), offset=bl_pin.ll(),
width=wbl_pin.width(), width=bl_pin.width(),
height=full_height)
wbl_bar_pin = self.cell_inst[0,col].get_pin("wbl_bar{0}".format(k))
self.add_layout_pin(text="wbl_bar{0}[{1}]".format(k,col),
layer="metal2",
offset=wbl_bar_pin.ll(),
width=wbl_bar_pin.width(),
height=full_height)
for k in range(self.num_read):
rbl_pin = self.cell_inst[0,col].get_pin("rbl{0}".format(k))
self.add_layout_pin(text="rbl{0}[{1}]".format(k,col),
layer="metal2",
offset=rbl_pin.ll(),
width=rbl_pin.width(),
height=full_height)
rbl_bar_pin = self.cell_inst[0,col].get_pin("rbl_bar{0}".format(k))
self.add_layout_pin(text="rbl_bar{0}[{1}]".format(k,col),
layer="metal2",
offset=rbl_bar_pin.ll(),
width=rbl_bar_pin.width(),
height=full_height) height=full_height)
# gnd offset is 0 in our cell, but it be non-zero # gnd offset is 0 in our cell, but it be non-zero
@ -287,6 +133,15 @@ class bitcell_array(design.design):
vdd_pins = self.cell_inst[row,0].get_pins("vdd") vdd_pins = self.cell_inst[row,0].get_pins("vdd")
gnd_pins = self.cell_inst[row,0].get_pins("gnd") gnd_pins = self.cell_inst[row,0].get_pins("gnd")
# add wl label and offset
for cell_row in row_list:
wl_pin = self.cell_inst[row,0].get_pin(cell_row)
self.add_layout_pin(text=cell_row+"[{0}]".format(row),
layer="metal1",
offset=wl_pin.ll(),
width=full_width,
height=wl_pin.height())
for gnd_pin in gnd_pins: for gnd_pin in gnd_pins:
if gnd_pin.layer=="metal1": if gnd_pin.layer=="metal1":
self.add_layout_pin(text="gnd", self.add_layout_pin(text="gnd",
@ -305,23 +160,6 @@ class bitcell_array(design.design):
width=full_width, width=full_width,
height=drc["minwidth_metal1"]) height=drc["minwidth_metal1"])
# add wl label and offset
for k in range(self.num_write):
wrow_pin = self.cell_inst[row,0].get_pin("wrow{0}".format(k))
self.add_layout_pin(text="wrow{0}[{1}]".format(k,row),
layer="metal1",
offset=wrow_pin.ll(),
width=full_width,
height=wrow_pin.height())
for k in range(self.num_read):
rrow_pin = self.cell_inst[row,0].get_pin("rrow{0}".format(k))
self.add_layout_pin(text="rrow{0}[{1}]".format(k,row),
layer="metal1",
offset=rrow_pin.ll(),
width=full_width,
height=rrow_pin.height())
# increments to the next row height # increments to the next row height
offset.y += self.cell.height offset.y += self.cell.height

View File

@ -146,18 +146,21 @@ class pbitcell(pgate.pgate):
self.rightmost_xpos = -self.leftmost_xpos self.rightmost_xpos = -self.leftmost_xpos
# bottommost position = gnd height + wrow height + rrow height # bottommost position = gnd height + wrow height + rrow height + space needed between tiled bitcells
array_tiling_offset = 0.5*drc["minwidth_metal2"]
self.botmost_ypos = -self.rail_tile_height \ self.botmost_ypos = -self.rail_tile_height \
- self.num_write*self.rowline_tile_height \ - self.num_write*self.rowline_tile_height \
- read_port_flag*(self.num_read*self.rowline_tile_height) - read_port_flag*(self.num_read*self.rowline_tile_height) \
- array_tiling_offset
# topmost position = height of the inverter + height of vdd # 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.topmost_ypos = self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height \
+ self.rail_tile_height + self.rail_tile_height
# calculations for the cell dimensions # calculations for the cell dimensions
array_vdd_overlap = 0.5*drc["minwidth_metal1"]
self.width = -2*self.leftmost_xpos self.width = -2*self.leftmost_xpos
self.height = self.topmost_ypos - self.botmost_ypos + 0.5*drc["minwidth_metal2"] - 0.5*drc["minwidth_metal1"] self.height = self.topmost_ypos - self.botmost_ypos - array_vdd_overlap
def add_storage(self): def add_storage(self):
@ -618,10 +621,9 @@ class pbitcell(pgate.pgate):
the well connections must be done piecewise to avoid pwell and nwell overlap. the well connections must be done piecewise to avoid pwell and nwell overlap.
""" """
cell_well_tiling_offset = 0.5*drc["minwidth_metal2"]
""" extend pwell to encompass entire nmos region of the cell up to the height of the inverter nmos well """ """ extend pwell to encompass entire nmos region of the cell up to the height of the inverter nmos well """
offset = vector(self.leftmost_xpos, self.botmost_ypos - cell_well_tiling_offset) offset = vector(self.leftmost_xpos, self.botmost_ypos)
well_height = -self.botmost_ypos + self.inverter_nmos.cell_well_height - drc["well_enclosure_active"] + cell_well_tiling_offset well_height = -self.botmost_ypos + self.inverter_nmos.cell_well_height - drc["well_enclosure_active"]
self.add_rect(layer="pwell", self.add_rect(layer="pwell",
offset=offset, offset=offset,
width=self.width, width=self.width,
@ -711,6 +713,49 @@ class pbitcell(pgate.pgate):
height=drc["minwidth_tx"]) height=drc["minwidth_tx"])
def list_bitcell_pins(self, col, row):
# Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array
bitcell_pins = []
for k in range(self.num_write):
bitcell_pins.append("wbl{0}[{1}]".format(k,col))
bitcell_pins.append("wbl_bar{0}[{1}]".format(k,col))
for k in range(self.num_read):
bitcell_pins.append("rbl{0}[{1}]".format(k,col))
bitcell_pins.append("rbl_bar{0}[{1}]".format(k,col))
for k in range(self.num_write):
bitcell_pins.append("wrow{0}[{1}]".format(k,row))
for k in range(self.num_read):
bitcell_pins.append("rrow{0}[{1}]".format(k,row))
bitcell_pins.append("vdd")
bitcell_pins.append("gnd")
return bitcell_pins
def list_row_pins(self):
# Creates a list of row pins
row_pins = []
for k in range(self.num_write):
row_pins.append("wrow{0}".format(k))
for k in range(self.num_read):
row_pins.append("rrow{0}".format(k))
return row_pins
def list_column_pins(self):
# Creates a list of column pins
column_pins = []
for k in range(self.num_write):
column_pins.append("wbl{0}".format(k))
column_pins.append("wbl_bar{0}".format(k))
for k in range(self.num_read):
column_pins.append("rbl{0}".format(k))
column_pins.append("rbl_bar{0}".format(k))
return column_pins
def add_fail(self): def add_fail(self):
# for failing drc when I want to observe the gds layout # for failing drc when I want to observe the gds layout
fail_position = vector(-4*drc["minwidth_metal1"], 0) # for tiling purposes fail_position = vector(-4*drc["minwidth_metal1"], 0) # for tiling purposes