Merge branch 'dev' into analytical_cleanup

This commit is contained in:
Hunter Nichols
2019-08-06 14:51:30 -07:00
105 changed files with 2331 additions and 2229 deletions
+230 -143
View File
@@ -17,18 +17,30 @@ import dummy_array
class replica_bitcell_array(design.design):
"""
Creates a bitcell arrow of cols x rows and then adds the replica and dummy columns
and rows for one or two read ports. Replica columns are on the left and right, respectively.
Creates a bitcell arrow of cols x rows and then adds the replica
and dummy columns and rows. Replica columns are on the left and
right, respectively and connected to the given bitcell ports.
Dummy are the outside columns/rows with WL and BL tied to gnd.
Requires a regular bitcell array, replica bitcell, and dummy bitcell (Bl/BR disconnected).
Requires a regular bitcell array, replica bitcell, and dummy
bitcell (Bl/BR disconnected).
"""
def __init__(self, cols, rows, name):
def __init__(self, cols, rows, left_rbl, right_rbl, bitcell_ports, name):
design.design.__init__(self, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols
self.row_size = rows
self.left_rbl = left_rbl
self.right_rbl = right_rbl
self.bitcell_ports = bitcell_ports
debug.check(left_rbl+right_rbl==len(self.read_ports),"Invalid number of RBLs for port configuration.")
debug.check(left_rbl+right_rbl==len(self.bitcell_ports),"Bitcell ports must match total RBLs.")
# Two dummy rows/cols plus replica for each port
self.extra_rows = 2 + left_rbl + right_rbl
self.extra_cols = 2 + left_rbl + right_rbl
self.create_netlist()
if not OPTS.netlist_only:
@@ -78,127 +90,201 @@ class replica_bitcell_array(design.design):
rows=self.row_size)
self.add_mod(self.bitcell_array)
# Replica bitline
self.replica_column = factory.create(module_type="replica_column",
rows=self.row_size + 4)
self.add_mod(self.replica_column)
# Replica bitlines
self.replica_columns = {}
for bit in range(self.left_rbl+self.right_rbl):
if bit<self.left_rbl:
replica_bit = bit+1
else:
replica_bit = bit+self.row_size+1
self.replica_columns[bit] = factory.create(module_type="replica_column",
rows=self.row_size,
left_rbl=self.left_rbl,
right_rbl=self.right_rbl,
replica_bit=replica_bit)
self.add_mod(self.replica_columns[bit])
# Dummy row
self.dummy_row = factory.create(module_type="dummy_array",
cols=self.column_size,
rows=1,
cols=self.column_size)
mirror=0)
self.add_mod(self.dummy_row)
# Dummy col
# Dummy col (mirror starting at first if odd replica+dummy rows)
self.dummy_col = factory.create(module_type="dummy_array",
cols=1,
rows=self.row_size + 4)
rows=self.row_size + self.extra_rows,
mirror=(self.left_rbl+1)%2)
self.add_mod(self.dummy_col)
def add_pins(self):
self.wl_names = [x for x in self.bitcell_array.pins if x.startswith("w")]
self.bl_names = [x for x in self.bitcell_array.pins if x.startswith("b")]
self.bitcell_array_wl_names = [x for x in self.bitcell_array.pins if x.startswith("w")]
self.bitcell_array_bl_names = [x for x in self.bitcell_array.pins if x.startswith("b")]
# top/bottom rows (in the middle)
self.replica_wl_names = ["replica_"+x for x in self.cell.pins if x.startswith("w")]
self.dummy_wl_names = ["dummy_"+x for x in self.cell.pins if x.startswith("w")]
self.dummy_bl_names = ["dummy_"+x for x in self.cell.pins if x.startswith("b")]
self.dummy_row_bl_names = self.bl_names
# These are the non-indexed names
self.dummy_cell_wl_names = ["dummy_"+x for x in self.cell.get_all_wl_names()]
self.dummy_cell_bl_names = ["dummy_"+x for x in self.cell.get_all_bitline_names()]
self.dummy_row_bl_names = self.bitcell_array_bl_names
# dummy row and replica on each side of the bitcell rows
self.replica_col_wl_names = [x+"_0" for x in self.dummy_wl_names] \
+ ["replica_"+x+"_0" for x in self.cell.list_all_wl_names()] \
+ self.wl_names \
+ ["replica_"+x+"_1" for x in self.cell.list_all_wl_names()] \
+ [x+"_1" for x in self.dummy_wl_names]
self.replica_bl_names = ["replica_"+x for x in self.cell.pins if x.startswith("b")]
# A dictionary because some ports may have nothing
self.rbl_bl_names = {}
self.rbl_br_names = {}
self.rbl_wl_names = {}
# left/right rows
# Create the full WL names include dummy, replica, and regular bit cells
self.replica_col_wl_names = []
self.replica_col_wl_names.extend(["{0}_bot".format(x) for x in self.dummy_cell_wl_names])
# Left port WLs (one dummy for each port when we allow >1 port)
for port in range(self.left_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x),port) for x in range(len(self.all_ports))]
# Keep track of the pin that is the RBL
self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
self.replica_col_wl_names.extend(wl_names)
# Regular WLs
self.replica_col_wl_names.extend(self.bitcell_array_wl_names)
# Right port WLs (one dummy for each port when we allow >1 port)
for port in range(self.left_rbl,self.left_rbl+self.right_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x),port) for x in range(len(self.all_ports))]
# Keep track of the pin that is the RBL
self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
self.replica_col_wl_names.extend(wl_names)
self.replica_col_wl_names.extend(["{0}_top".format(x) for x in self.dummy_cell_wl_names])
# Left/right dummy columns are connected identically to the replica column
self.dummy_col_wl_names = self.replica_col_wl_names
self.add_pin_list(self.bl_names)
self.add_pin_list([x+"_0" for x in self.replica_bl_names])
self.add_pin_list([x+"_1" for x in self.replica_bl_names])
self.add_pin_list([x for x in self.replica_col_wl_names if not x.startswith("dummy")])
self.add_pin("vdd")
self.add_pin("gnd")
# Per port bitline names
self.replica_bl_names = {}
self.replica_wl_names = {}
# Array of all port bitline names
for port in range(self.left_rbl+self.right_rbl):
left_names=["rbl_{0}_{1}".format(self.cell.get_bl_name(x),port) for x in range(len(self.all_ports))]
right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x),port) for x in range(len(self.all_ports))]
# Keep track of the left pins that are the RBL
self.rbl_bl_names[port]=left_names[self.bitcell_ports[port]]
self.rbl_br_names[port]=right_names[self.bitcell_ports[port]]
# Interleave the left and right lists
bl_names = [x for t in zip(left_names, right_names) for x in t]
self.replica_bl_names[port] = bl_names
wl_names = ["rbl_{0}_{1}".format(x,port) for x in self.cell.get_all_wl_names()]
#wl_names[port] = "rbl_wl{}".format(port)
self.replica_wl_names[port] = wl_names
# External pins
self.add_pin_list(self.bitcell_array_bl_names, "INOUT")
# Need to sort by port order since dictionary values may not be in order
bl_names = [self.rbl_bl_names[x] for x in sorted(self.rbl_bl_names.keys())]
br_names = [self.rbl_br_names[x] for x in sorted(self.rbl_br_names.keys())]
for (bl_name,br_name) in zip(bl_names,br_names):
self.add_pin(bl_name,"OUTPUT")
self.add_pin(br_name,"OUTPUT")
self.add_pin_list(self.bitcell_array_wl_names, "INPUT")
# Need to sort by port order since dictionary values may not be in order
wl_names = [self.rbl_wl_names[x] for x in sorted(self.rbl_wl_names.keys())]
for pin_name in wl_names:
self.add_pin(pin_name,"INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def create_instances(self):
""" Create the module instances used in this design """
supplies = ["vdd", "gnd"]
# Used for names/dimensions only
self.cell = factory.create(module_type="bitcell")
# Main array
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
mod=self.bitcell_array)
self.connect_inst(self.bitcell_array.pins)
self.connect_inst(self.bitcell_array_bl_names + self.bitcell_array_wl_names + supplies)
# Replica columns (two even if one port for now)
self.replica_col_left_inst=self.add_inst(name="replica_col_left",
mod=self.replica_column)
self.connect_inst([x+"_0" for x in self.replica_bl_names] + self.replica_col_wl_names + supplies)
self.replica_col_right_inst=self.add_inst(name="replica_col_right",
mod=self.replica_column)
self.connect_inst([x+"_1" for x in self.replica_bl_names] + self.replica_col_wl_names[::-1] + supplies)
# Replica columns
self.replica_col_inst = {}
for port in range(self.left_rbl+self.right_rbl):
self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port),
mod=self.replica_columns[port])
self.connect_inst(self.replica_bl_names[port] + self.replica_col_wl_names + supplies)
# Replica rows with replica bitcell
self.dummy_row_bottop_inst=self.add_inst(name="dummy_row_bottop",
mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + [x+"_0" for x in self.replica_wl_names] + supplies)
self.dummy_row_topbot_inst=self.add_inst(name="dummy_row_topbot",
mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + [x+"_1" for x in self.replica_wl_names] + supplies)
# Dummy rows under the bitcell array (connected with with the replica cell wl)
self.dummy_row_replica_inst = {}
for port in range(self.left_rbl+self.right_rbl):
self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port),
mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names[port] + supplies)
# Dummy rows without replica bitcell
self.dummy_row_botbot_inst=self.add_inst(name="dummy_row_botbot",
# Top/bottom dummy rows
self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot",
mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + [x+"_0" for x in self.dummy_wl_names] + supplies)
self.dummy_row_toptop_inst=self.add_inst(name="dummy_row_toptop",
self.connect_inst(self.dummy_row_bl_names + [x+"_bot" for x in self.dummy_cell_wl_names] + supplies)
self.dummy_row_top_inst=self.add_inst(name="dummy_row_top",
mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + [x+"_1" for x in self.dummy_wl_names] + supplies)
self.connect_inst(self.dummy_row_bl_names + [x+"_top" for x in self.dummy_cell_wl_names] + supplies)
# Dummy columns
# Left/right Dummy columns
self.dummy_col_left_inst=self.add_inst(name="dummy_col_left",
mod=self.dummy_col)
self.connect_inst([x+"_0" for x in self.dummy_bl_names] + self.dummy_col_wl_names + supplies)
self.connect_inst([x+"_left" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
self.dummy_col_right_inst=self.add_inst(name="dummy_col_right",
mod=self.dummy_col)
self.connect_inst([x+"_1" for x in self.dummy_bl_names] + self.dummy_col_wl_names + supplies)
self.connect_inst([x+"_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
def create_layout(self):
self.height = (self.row_size+4)*self.dummy_row.height
self.width = (self.column_size+4)*self.replica_column.width
self.height = (self.row_size+self.extra_rows)*self.dummy_row.height
self.width = (self.column_size+self.extra_cols)*self.cell.width
# This is a bitcell x bitcell offset to scale
offset = vector(self.replica_column.width, self.dummy_row.height)
offset = vector(self.cell.width, self.cell.height)
self.bitcell_array_inst.place(offset=[0,0])
self.replica_col_left_inst.place(offset=offset.scale(-1,-2))
self.replica_col_right_inst.place(offset=offset.scale(0,2)+self.bitcell_array_inst.ur(),
mirror="MX")
self.dummy_row_toptop_inst.place(offset=offset.scale(0,2)+self.bitcell_array_inst.ul(),
mirror="MX")
self.dummy_row_topbot_inst.place(offset=offset.scale(0,0)+self.bitcell_array_inst.ul())
self.dummy_row_bottop_inst.place(offset=offset.scale(0,0),
mirror="MX")
self.dummy_row_botbot_inst.place(offset=offset.scale(0,-2))
self.dummy_col_left_inst.place(offset=offset.scale(-2,-2))
self.dummy_col_right_inst.place(offset=offset.scale(1,-2)+self.bitcell_array_inst.lr())
# To the left of the bitcell array
for bit in range(self.left_rbl):
self.replica_col_inst[bit].place(offset=offset.scale(-bit-1,-self.left_rbl-1))
# To the right of the bitcell array
for bit in range(self.right_rbl):
self.replica_col_inst[self.left_rbl+bit].place(offset=offset.scale(bit,-self.left_rbl-1)+self.bitcell_array_inst.lr())
self.translate_all(offset.scale(-2,-2))
# Far top dummy row (first row above array is NOT flipped)
flip_dummy = self.right_rbl%2
self.dummy_row_top_inst.place(offset=offset.scale(0,self.right_rbl+flip_dummy)+self.bitcell_array_inst.ul(),
mirror="MX" if flip_dummy else "R0")
# Far bottom dummy row (first row below array IS flipped)
flip_dummy = (self.left_rbl+1)%2
self.dummy_row_bot_inst.place(offset=offset.scale(0,-self.left_rbl-1+flip_dummy),
mirror="MX" if flip_dummy else "R0")
# Far left dummy col
self.dummy_col_left_inst.place(offset=offset.scale(-self.left_rbl-1,-self.left_rbl-1))
# Far right dummy col
self.dummy_col_right_inst.place(offset=offset.scale(self.right_rbl,-self.left_rbl-1)+self.bitcell_array_inst.lr())
# Replica dummy rows
for bit in range(self.left_rbl):
self.dummy_row_replica_inst[bit].place(offset=offset.scale(0,-bit-bit%2),
mirror="R0" if bit%2 else "MX")
for bit in range(self.right_rbl):
self.dummy_row_replica_inst[self.left_rbl+bit].place(offset=offset.scale(0,bit+bit%2)+self.bitcell_array_inst.ul(),
mirror="MX" if bit%2 else "R0")
self.translate_all(offset.scale(-1-self.left_rbl,-1-self.left_rbl))
self.add_layout_pins()
@@ -216,90 +302,77 @@ class replica_bitcell_array(design.design):
if pin_name.startswith("wl"):
pin_list = self.bitcell_array_inst.get_pins(pin_name)
for pin in pin_list:
self.add_layout_pin_rect_center(text=pin_name,
layer=pin.layer,
offset=pin.center(),
width=self.width,
height=pin.height())
self.add_layout_pin(text=pin_name,
layer=pin.layer,
offset=pin.ll().scale(0,1),
width=self.width,
height=pin.height())
elif pin_name.startswith("bl") or pin_name.startswith("br"):
pin_list = self.bitcell_array_inst.get_pins(pin_name)
for pin in pin_list:
self.add_layout_pin_rect_center(text=pin_name,
layer=pin.layer,
offset=pin.center(),
width=pin.width(),
height=self.height)
self.add_layout_pin(text=pin_name,
layer=pin.layer,
offset=pin.ll().scale(1,0),
width=pin.width(),
height=self.height)
for index,(side1,side2) in enumerate([("bottop","left"),("topbot","right")]):
inst = getattr(self, "dummy_row_{}_inst".format(side1))
pin_names = inst.mod.get_pin_names()
for pin_name in pin_names:
if pin_name.startswith("wl"):
pin_list = inst.get_pins(pin_name)
for pin in pin_list:
name = "replica_{0}_{1}".format(pin_name,index)
self.add_layout_pin_rect_center(text=name,
layer=pin.layer,
offset=pin.center(),
width=self.width,
height=pin.height())
# Replica wordlines
for port in range(self.left_rbl+self.right_rbl):
inst = self.replica_col_inst[port]
for (pin_name,wl_name) in zip(self.cell.get_all_wl_names(),self.replica_wl_names[port]):
# +1 for dummy row
pin_bit = port+1
# +row_size if above the array
if port>=self.left_rbl:
pin_bit += self.row_size
pin_name += "_{}".format(pin_bit)
pin = inst.get_pin(pin_name)
if wl_name in self.rbl_wl_names.values():
self.add_layout_pin(text=wl_name,
layer=pin.layer,
offset=pin.ll().scale(0,1),
width=self.width,
height=pin.height())
# Replica columns
for index,side in enumerate(["left","right"]):
inst = getattr(self, "replica_col_{}_inst".format(side))
pin_names = inst.mod.get_pin_names()
for pin_name in pin_names:
if pin_name.startswith("bl") or pin_name.startswith("br"):
pin_list = inst.get_pins(pin_name)
for pin in pin_list:
name = "replica_{0}_{1}".format(pin_name,index)
self.add_layout_pin(text=name,
layer=pin.layer,
offset=pin.ll().scale(1,0),
width=pin.width(),
height=self.height)
# Replica bitlines
for port in range(self.left_rbl+self.right_rbl):
inst = self.replica_col_inst[port]
for (pin_name, bl_name) in zip(self.cell.get_all_bitline_names(),self.replica_bl_names[port]):
pin = inst.get_pin(pin_name)
if bl_name in self.rbl_bl_names or bl_name in self.rbl_br_names:
name = bl_name
else:
name = "rbl_{0}_{1}".format(pin_name,port)
self.add_layout_pin(text=name,
layer=pin.layer,
offset=pin.ll().scale(1,0),
width=pin.width(),
height=self.height)
for pin_name in ["vdd","gnd"]:
for inst in [self.bitcell_array_inst,
self.replica_col_left_inst, self.replica_col_right_inst,
self.dummy_col_left_inst, self.dummy_col_right_inst,
self.dummy_row_toptop_inst, self.dummy_row_topbot_inst,
self.dummy_row_bottop_inst, self.dummy_row_botbot_inst]:
for inst in self.insts:
pin_list = inst.get_pins(pin_name)
for pin in pin_list:
self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
# Non-pins
for side in ["botbot", "toptop"]:
inst = getattr(self, "dummy_row_{}_inst".format(side))
pin_names = inst.mod.get_pin_names()
for pin_name in pin_names:
if pin_name.startswith("wl"):
pin_list = inst.get_pins(pin_name)
for pin in pin_list:
self.add_rect_center(layer=pin.layer,
offset=pin.center(),
width=self.width,
height=pin.height())
for side in ["left", "right"]:
inst = getattr(self, "dummy_col_{}_inst".format(side))
pin_names = inst.mod.get_pin_names()
for pin_name in pin_names:
if pin_name.startswith("b"):
pin_list = inst.get_pins(pin_name)
for pin in pin_list:
self.add_rect_center(layer=pin.layer,
offset=pin.center(),
width=pin.width(),
height=self.height)
def get_rbl_wl_name(self, port):
""" Return the WL for the given RBL port """
return self.rbl_wl_names[port]
def get_rbl_bl_name(self, port):
""" Return the BL for the given RBL port """
return self.rbl_bl_names[port]
def get_rbl_br_name(self, port):
""" Return the BR for the given RBL port """
return self.rbl_br_names[port]
def analytical_delay(self, corner, slew, load):
"""Returns relative delay of the bitline in the bitcell array"""
@@ -307,7 +380,7 @@ class replica_bitcell_array(design.design):
#The load being driven/drained is mostly the bitline but could include the sense amp or the column mux.
#The load from the bitlines is due to the drain capacitances from all the other bitlines and wire parasitics.
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
wire_unit_load = .05 * drain_load #Wires add 5% to this.
wire_unit_load = 0.05 * drain_load #Wires add 5% to this.
bitline_load = (drain_load+wire_unit_load)*self.row_size
return [self.cell.analytical_delay(corner, slew, load+bitline_load)]
@@ -318,7 +391,7 @@ class replica_bitcell_array(design.design):
# Dynamic Power from Bitline
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap()
bl_swing = parameter["rbl_height_percentage"]
bl_swing = OPTS.rbl_delay_percentage
freq = spice["default_event_rate"]
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
@@ -346,3 +419,17 @@ class replica_bitcell_array(design.design):
bitcell_wl_cin = self.cell.get_wl_cin()
total_cin = bitcell_wl_cin * self.column_size
return total_cin
def graph_exclude_bits(self, targ_row, targ_col):
"""Excludes bits in column from being added to graph except target"""
self.bitcell_array.graph_exclude_bits(targ_row, targ_col)
def graph_exclude_replica_col_bits(self):
"""Exclude all replica/dummy cells in the replica columns except the replica bit."""
for port in range(self.left_rbl+self.right_rbl):
self.replica_columns[port].exclude_all_but_replica()
def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell."""
return self.bitcell_array.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col)