PEP8 Formatting

This commit is contained in:
mrg 2020-03-05 11:58:36 -08:00
parent 7adeef6c9e
commit 9c1f0657dd
1 changed files with 154 additions and 179 deletions

View File

@ -17,9 +17,9 @@ from globals import OPTS
class bank(design.design): class bank(design.design):
""" """
Dynamically generated a single bank including bitcell array, Dynamically generated a single bank including bitcell array,
hierarchical_decoder, precharge, (optional column_mux and column decoder), hierarchical_decoder, precharge, (optional column_mux and column decoder),
write driver and sense amplifiers. write driver and sense amplifiers.
This can create up to two ports in any combination: rw, w, r. This can create up to two ports in any combination: rw, w, r.
""" """
def __init__(self, sram_config, name=""): def __init__(self, sram_config, name=""):
@ -27,15 +27,15 @@ class bank(design.design):
self.sram_config = sram_config self.sram_config = sram_config
sram_config.set_local_config(self) sram_config.set_local_config(self)
if self.write_size: if self.write_size:
self.num_wmasks = int(self.word_size/self.write_size) self.num_wmasks = int(self.word_size / self.write_size)
else: else:
self.num_wmasks = 0 self.num_wmasks = 0
if name == "": if name == "":
name = "bank_{0}_{1}".format(self.word_size, self.num_words) name = "bank_{0}_{1}".format(self.word_size, self.num_words)
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words)) debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,
self.num_words))
# The local control signals are gated when we have bank select logic, # The local control signals are gated when we have bank select logic,
# so this prefix will be added to all of the input signals to create # so this prefix will be added to all of the input signals to create
@ -47,18 +47,17 @@ class bank(design.design):
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
debug.check(len(self.all_ports)<=2,"Bank layout cannot handle more than two ports.") debug.check(len(self.all_ports)<=2,
"Bank layout cannot handle more than two ports.")
self.create_layout() self.create_layout()
self.add_boundary() self.add_boundary()
def create_netlist(self): def create_netlist(self):
self.compute_sizes() self.compute_sizes()
self.add_modules() self.add_modules()
self.add_pins() # Must create the replica bitcell array first self.add_pins() # Must create the replica bitcell array first
self.create_instances() self.create_instances()
def create_layout(self): def create_layout(self):
self.place_instances() self.place_instances()
@ -66,35 +65,34 @@ class bank(design.design):
self.route_layout() self.route_layout()
# Can remove the following, but it helps for debug! # Can remove the following, but it helps for debug!
#self.add_lvs_correspondence_points() # self.add_lvs_correspondence_points()
# Remember the bank center for further placement # Remember the bank center for further placement
self.bank_array_ll = self.offset_all_coordinates().scale(-1,-1) self.bank_array_ll = self.offset_all_coordinates().scale(-1, -1)
self.bank_array_ur = self.bitcell_array_inst.ur() self.bank_array_ur = self.bitcell_array_inst.ur()
self.bank_array_ul = self.bitcell_array_inst.ul() self.bank_array_ul = self.bitcell_array_inst.ul()
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
""" Adding pins for Bank module""" """ Adding pins for Bank module"""
for port in self.read_ports: for port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("dout{0}_{1}".format(port,bit),"OUTPUT") self.add_pin("dout{0}_{1}".format(port, bit), "OUTPUT")
for port in self.all_ports: for port in self.all_ports:
self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUTPUT") self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]), "OUTPUT")
for port in self.write_ports: for port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.add_pin("din{0}_{1}".format(port,bit),"INPUT") self.add_pin("din{0}_{1}".format(port,bit), "INPUT")
for port in self.all_ports: for port in self.all_ports:
for bit in range(self.addr_size): for bit in range(self.addr_size):
self.add_pin("addr{0}_{1}".format(port,bit),"INPUT") self.add_pin("addr{0}_{1}".format(port,bit), "INPUT")
# For more than one bank, we have a bank select and name # For more than one bank, we have a bank select and name
# the signals gated_*. # the signals gated_*.
if self.num_banks > 1: if self.num_banks > 1:
for port in self.all_ports: for port in self.all_ports:
self.add_pin("bank_sel{}".format(port),"INPUT") self.add_pin("bank_sel{}".format(port), "INPUT")
for port in self.read_ports: for port in self.read_ports:
self.add_pin("s_en{0}".format(port), "INPUT") self.add_pin("s_en{0}".format(port), "INPUT")
for port in self.all_ports: for port in self.all_ports:
@ -102,12 +100,11 @@ class bank(design.design):
for port in self.write_ports: for port in self.write_ports:
self.add_pin("w_en{0}".format(port), "INPUT") self.add_pin("w_en{0}".format(port), "INPUT")
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
self.add_pin("bank_wmask{0}_{1}".format(port,bit),"INPUT") self.add_pin("bank_wmask{0}_{1}".format(port, bit), "INPUT")
for port in self.all_ports: for port in self.all_ports:
self.add_pin("wl_en{0}".format(port), "INPUT") self.add_pin("wl_en{0}".format(port), "INPUT")
self.add_pin("vdd","POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd","GROUND") self.add_pin("gnd", "GROUND")
def route_layout(self): def route_layout(self):
""" Create routing amoung the modules """ """ Create routing amoung the modules """
@ -124,7 +121,7 @@ class bank(design.design):
self.route_supplies() self.route_supplies()
def route_rbl(self,port): def route_rbl(self, port):
""" Route the rbl_bl and rbl_wl """ """ Route the rbl_bl and rbl_wl """
bl_pin_name = self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]) bl_pin_name = self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
@ -135,8 +132,6 @@ class bank(design.design):
height=bl_pin.height(), height=bl_pin.height(),
width=bl_pin.width()) width=bl_pin.width())
def route_bitlines(self, port): def route_bitlines(self, port):
""" Route the bitlines depending on the port type rw, w, or r. """ """ Route the bitlines depending on the port type rw, w, or r. """
@ -146,7 +141,6 @@ class bank(design.design):
self.route_port_data_out(port) self.route_port_data_out(port)
self.route_port_data_to_bitcell_array(port) self.route_port_data_to_bitcell_array(port)
def create_instances(self): def create_instances(self):
""" Create the instances of the netlist. """ """ Create the instances of the netlist. """
@ -161,19 +155,18 @@ class bank(design.design):
Compute the empty instance offsets for port0 and port1 (if needed) Compute the empty instance offsets for port0 and port1 (if needed)
""" """
self.port_data_offsets = [None]*len(self.all_ports) self.port_data_offsets = [None] * len(self.all_ports)
self.port_address_offsets = [None]*len(self.all_ports) self.port_address_offsets = [None] * len(self.all_ports)
self.column_decoder_offsets = [None]*len(self.all_ports)
self.bank_select_offsets = [None]*len(self.all_ports)
self.column_decoder_offsets = [None] * len(self.all_ports)
self.bank_select_offsets = [None] * len(self.all_ports)
# The center point for these cells are the upper-right corner of # The center point for these cells are the upper-right corner of
# the bitcell array. # the bitcell array.
# The port address decoder/driver logic is placed on the right and mirrored on Y-axis. # The port address decoder/driver logic is placed on the right and mirrored on Y-axis.
# The port data write/sense/precharge/mux is placed on the top and mirrored on the X-axis. # The port data write/sense/precharge/mux is placed on the top and mirrored on the X-axis.
self.bitcell_array_top = self.bitcell_array.height self.bitcell_array_top = self.bitcell_array.height
self.bitcell_array_right = self.bitcell_array.width self.bitcell_array_right = self.bitcell_array.width
# These are the offsets of the main array (excluding dummy and replica rows/cols) # These are the offsets of the main array (excluding dummy and replica rows/cols)
self.main_bitcell_array_top = self.bitcell_array.bitcell_array_inst.uy() self.main_bitcell_array_top = self.bitcell_array.bitcell_array_inst.uy()
@ -185,7 +178,6 @@ class bank(design.design):
self.compute_instance_port0_offsets() self.compute_instance_port0_offsets()
if len(self.all_ports)==2: if len(self.all_ports)==2:
self.compute_instance_port1_offsets() self.compute_instance_port1_offsets()
def compute_instance_port0_offsets(self): def compute_instance_port0_offsets(self):
""" """
@ -196,29 +188,30 @@ class bank(design.design):
# UPPER RIGHT QUADRANT # UPPER RIGHT QUADRANT
# Bitcell array is placed at (0,0) # Bitcell array is placed at (0,0)
self.bitcell_array_offset = vector(0,0) self.bitcell_array_offset = vector(0, 0)
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# Below the bitcell array # Below the bitcell array
self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width,0) self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width, 0)
# UPPER LEFT QUADRANT # UPPER LEFT QUADRANT
# To the left of the bitcell array # To the left of the bitcell array
x_offset = self.m2_gap + self.port_address.width x_offset = self.m2_gap + self.port_address.width
self.port_address_offsets[port] = vector(-x_offset,self.main_bitcell_array_bottom) self.port_address_offsets[port] = vector(-x_offset,
self.main_bitcell_array_bottom)
# LOWER LEFT QUADRANT # LOWER LEFT QUADRANT
# Place the col decoder left aligned with wordline driver # Place the col decoder left aligned with wordline driver
# This is also placed so that it's supply rails do not align with the SRAM-level # This is also placed so that it's supply rails do not align with the SRAM-level
# control logic to allow control signals to easily pass over in M3 # control logic to allow control signals to easily pass over in M3
# by placing 1/2 a cell pitch down # by placing 1/2 a cell pitch down
x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0: if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = 0.5*self.dff.height + self.column_decoder.height y_offset = 0.5 * self.dff.height + self.column_decoder.height
else: else:
y_offset = 0 y_offset = 0
self.column_decoder_offsets[port] = vector(-x_offset,-y_offset) self.column_decoder_offsets[port] = vector(-x_offset, -y_offset)
# Bank select gets placed below the column decoder (x_offset doesn't change) # Bank select gets placed below the column decoder (x_offset doesn't change)
if self.col_addr_size > 0: if self.col_addr_size > 0:
@ -227,7 +220,7 @@ class bank(design.design):
y_offset = self.port_address_offsets[port].y y_offset = self.port_address_offsets[port].y
if self.num_banks > 1: if self.num_banks > 1:
y_offset += self.bank_select.height + drc("well_to_well") y_offset += self.bank_select.height + drc("well_to_well")
self.bank_select_offsets[port] = vector(-x_offset,-y_offset) self.bank_select_offsets[port] = vector(-x_offset, -y_offset)
def compute_instance_port1_offsets(self): def compute_instance_port1_offsets(self):
""" """
@ -246,18 +239,19 @@ class bank(design.design):
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# To the left of the bitcell array # To the left of the bitcell array
x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap
self.port_address_offsets[port] = vector(x_offset,self.main_bitcell_array_bottom) self.port_address_offsets[port] = vector(x_offset,
self.main_bitcell_array_bottom)
# UPPER RIGHT QUADRANT # UPPER RIGHT QUADRANT
# Place the col decoder right aligned with wordline driver # Place the col decoder right aligned with wordline driver
# Above the bitcell array with a well spacing # Above the bitcell array with a well spacing
x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0: if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = self.bitcell_array_top + 0.5*self.dff.height + self.column_decoder.height y_offset = self.bitcell_array_top + 0.5 * self.dff.height + self.column_decoder.height
else: else:
y_offset = self.bitcell_array_top y_offset = self.bitcell_array_top
self.column_decoder_offsets[port] = vector(x_offset,y_offset) self.column_decoder_offsets[port] = vector(x_offset, y_offset)
# Bank select gets placed above the column decoder (x_offset doesn't change) # Bank select gets placed above the column decoder (x_offset doesn't change)
if self.col_addr_size > 0: if self.col_addr_size > 0:
@ -265,7 +259,7 @@ class bank(design.design):
self.port_data[port].column_mux_offset.y + self.port_data[port].column_mux_array.height) self.port_data[port].column_mux_offset.y + self.port_data[port].column_mux_array.height)
else: else:
y_offset = self.port_address_offsets[port].y y_offset = self.port_address_offsets[port].y
self.bank_select_offsets[port] = vector(x_offset,y_offset) self.bank_select_offsets[port] = vector(x_offset, y_offset)
def place_instances(self): def place_instances(self):
""" Place the instances. """ """ Place the instances. """
@ -281,19 +275,20 @@ class bank(design.design):
self.place_column_decoder(self.column_decoder_offsets) self.place_column_decoder(self.column_decoder_offsets)
self.place_bank_select(self.bank_select_offsets) self.place_bank_select(self.bank_select_offsets)
def compute_sizes(self): def compute_sizes(self):
""" Computes the required sizes to create the bank """ """ Computes the required sizes to create the bank """
self.num_cols = int(self.words_per_row*self.word_size) self.num_cols = int(self.words_per_row * self.word_size)
self.num_rows = int(self.num_words / self.words_per_row) self.num_rows = int(self.num_words / self.words_per_row)
self.row_addr_size = int(log(self.num_rows, 2)) self.row_addr_size = int(log(self.num_rows, 2))
self.col_addr_size = int(log(self.words_per_row, 2)) self.col_addr_size = int(log(self.words_per_row, 2))
self.addr_size = self.col_addr_size + self.row_addr_size self.addr_size = self.col_addr_size + self.row_addr_size
debug.check(self.num_rows*self.num_cols==self.word_size*self.num_words,"Invalid bank sizes.") debug.check(self.num_rows * self.num_cols==self.word_size * self.num_words,
debug.check(self.addr_size==self.col_addr_size + self.row_addr_size,"Invalid address break down.") "Invalid bank sizes.")
debug.check(self.addr_size==self.col_addr_size + self.row_addr_size,
"Invalid address break down.")
# The order of the control signals on the control bus: # The order of the control signals on the control bus:
self.input_control_signals = [] self.input_control_signals = []
@ -312,13 +307,13 @@ class bank(design.design):
self.num_control_lines = [len(x) for x in self.input_control_signals] self.num_control_lines = [len(x) for x in self.input_control_signals]
# The width of this bus is needed to place other modules (e.g. decoder) for each port # The width of this bus is needed to place other modules (e.g. decoder) for each port
self.central_bus_width = [self.m2_pitch*x + self.m2_width for x in self.num_control_lines] self.central_bus_width = [self.m2_pitch * x + self.m2_width for x in self.num_control_lines]
# These will be outputs of the gaters if this is multibank, if not, normal signals. # These will be outputs of the gaters if this is multibank, if not, normal signals.
self.control_signals = [] self.control_signals = []
for port in self.all_ports: for port in self.all_ports:
if self.num_banks > 1: if self.num_banks > 1:
self.control_signals.append(["gated_"+str for str in self.input_control_signals[port]]) self.control_signals.append(["gated_" + str for str in self.input_control_signals[port]])
else: else:
self.control_signals.append(self.input_control_signals[port]) self.control_signals.append(self.input_control_signals[port])
@ -326,19 +321,18 @@ class bank(design.design):
if self.col_addr_size>0: if self.col_addr_size>0:
self.num_col_addr_lines = 2**self.col_addr_size self.num_col_addr_lines = 2**self.col_addr_size
else: else:
self.num_col_addr_lines = 0 self.num_col_addr_lines = 0
self.col_addr_bus_width = self.m2_pitch*self.num_col_addr_lines self.col_addr_bus_width = self.m2_pitch * self.num_col_addr_lines
# A space for wells or jogging m2 # A space for wells or jogging m2
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("nwell_enclose_active"), self.m2_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"),
3*self.m2_pitch) 3 * self.m2_pitch)
def add_modules(self): def add_modules(self):
""" Add all the modules using the class loader """ """ Add all the modules using the class loader """
# create arrays of bitline and bitline_bar names for read, write, or all ports # create arrays of bitline and bitline_bar names for read, write, or all ports
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type="bitcell")
self.bl_names = self.bitcell.get_all_bl_names() self.bl_names = self.bitcell.get_all_bl_names()
self.br_names = self.bitcell.get_all_br_names() self.br_names = self.bitcell.get_all_br_names()
self.wl_names = self.bitcell.get_all_wl_names() self.wl_names = self.bitcell.get_all_wl_names()
@ -352,13 +346,11 @@ class bank(design.design):
self.port_data.append(temp_pre) self.port_data.append(temp_pre)
self.add_mod(self.port_data[port]) self.add_mod(self.port_data[port])
self.port_address = factory.create(module_type="port_address", self.port_address = factory.create(module_type="port_address",
cols=self.num_cols, cols=self.num_cols,
rows=self.num_rows) rows=self.num_rows)
self.add_mod(self.port_address) self.add_mod(self.port_address)
self.port_rbl_map = self.all_ports self.port_rbl_map = self.all_ports
self.num_rbl = len(self.all_ports) self.num_rbl = len(self.all_ports)
@ -370,22 +362,20 @@ class bank(design.design):
bitcell_ports=self.all_ports) bitcell_ports=self.all_ports)
self.add_mod(self.bitcell_array) self.add_mod(self.bitcell_array)
if(self.num_banks > 1): if(self.num_banks > 1):
self.bank_select = factory.create(module_type="bank_select") self.bank_select = factory.create(module_type="bank_select")
self.add_mod(self.bank_select) self.add_mod(self.bank_select)
def create_bitcell_array(self): def create_bitcell_array(self):
""" Creating Bitcell Array """ """ Creating Bitcell Array """
self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array", self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array",
mod=self.bitcell_array) mod=self.bitcell_array)
temp = [] temp = []
for col in range(self.num_cols): for col in range(self.num_cols):
for bitline in self.bitline_names: for bitline in self.bitline_names:
temp.append("{0}_{1}".format(bitline,col)) temp.append("{0}_{1}".format(bitline, col))
for rbl in range(self.num_rbl): for rbl in range(self.num_rbl):
rbl_bl_name=self.bitcell_array.get_rbl_bl_name(rbl) rbl_bl_name=self.bitcell_array.get_rbl_bl_name(rbl)
temp.append(rbl_bl_name) temp.append(rbl_bl_name)
@ -393,23 +383,21 @@ class bank(design.design):
temp.append(rbl_br_name) temp.append(rbl_br_name)
for row in range(self.num_rows): for row in range(self.num_rows):
for wordline in self.wl_names: for wordline in self.wl_names:
temp.append("{0}_{1}".format(wordline,row)) temp.append("{0}_{1}".format(wordline, row))
for port in self.all_ports: for port in self.all_ports:
temp.append("wl_en{0}".format(port)) temp.append("wl_en{0}".format(port))
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_bitcell_array(self, offset): def place_bitcell_array(self, offset):
""" Placing Bitcell Array """ """ Placing Bitcell Array """
self.bitcell_array_inst.place(offset) self.bitcell_array_inst.place(offset)
def create_port_data(self): def create_port_data(self):
""" Creating Port Data """ """ Creating Port Data """
self.port_data_inst = [None]*len(self.all_ports) self.port_data_inst = [None] * len(self.all_ports)
for port in self.all_ports: for port in self.all_ports:
self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port), self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port),
mod=self.port_data[port]) mod=self.port_data[port])
@ -419,17 +407,17 @@ class bank(design.design):
rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port]) rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port])
temp.append(rbl_bl_name) temp.append(rbl_bl_name)
temp.append(rbl_br_name) temp.append(rbl_br_name)
for col in range(self.num_cols): for col in range(self.num_cols):
temp.append("{0}_{1}".format(self.bl_names[port],col)) temp.append("{0}_{1}".format(self.bl_names[port], col))
temp.append("{0}_{1}".format(self.br_names[port],col)) temp.append("{0}_{1}".format(self.br_names[port], col))
if port in self.read_ports: if port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("dout{0}_{1}".format(port,bit)) temp.append("dout{0}_{1}".format(port, bit))
if port in self.write_ports: if port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("din{0}_{1}".format(port,bit)) temp.append("din{0}_{1}".format(port, bit))
# Will be empty if no col addr lines # Will be empty if no col addr lines
sel_names = ["sel{0}_{1}".format(port,x) for x in range(self.num_col_addr_lines)] sel_names = ["sel{0}_{1}".format(port, x) for x in range(self.num_col_addr_lines)]
temp.extend(sel_names) temp.extend(sel_names)
if port in self.read_ports: if port in self.read_ports:
temp.append("s_en{0}".format(port)) temp.append("s_en{0}".format(port))
@ -438,17 +426,16 @@ class bank(design.design):
temp.append("w_en{0}".format(port)) temp.append("w_en{0}".format(port))
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
temp.append("bank_wmask{0}_{1}".format(port, bit)) temp.append("bank_wmask{0}_{1}".format(port, bit))
temp.extend(["vdd","gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_port_data(self, offsets): def place_port_data(self, offsets):
""" Placing Port Data """ """ Placing Port Data """
for port in self.all_ports: for port in self.all_ports:
# Top one is unflipped, bottom is flipped along X direction # Top one is unflipped, bottom is flipped along X direction
if port%2 == 1: if port % 2 == 1:
mirror = "R0" mirror = "R0"
else: else:
mirror = "MX" mirror = "MX"
@ -457,42 +444,40 @@ class bank(design.design):
def create_port_address(self): def create_port_address(self):
""" Create the hierarchical row decoder """ """ Create the hierarchical row decoder """
self.port_address_inst = [None]*len(self.all_ports) self.port_address_inst = [None] * len(self.all_ports)
for port in self.all_ports: for port in self.all_ports:
self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port), self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port),
mod=self.port_address) mod=self.port_address)
temp = [] temp = []
for bit in range(self.row_addr_size): for bit in range(self.row_addr_size):
temp.append("addr{0}_{1}".format(port,bit+self.col_addr_size)) temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size))
temp.append("wl_en{0}".format(port)) temp.append("wl_en{0}".format(port))
for row in range(self.num_rows): for row in range(self.num_rows):
temp.append("{0}_{1}".format(self.wl_names[port],row)) temp.append("{0}_{1}".format(self.wl_names[port], row))
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_port_address(self, offsets): def place_port_address(self, offsets):
""" Place the hierarchical row decoder """ """ Place the hierarchical row decoder """
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.") debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.")
# The address and control bus will be in between decoder and the main memory array # The address and control bus will be in between decoder and the main memory array
# This bus will route address bits to the decoder input and column mux inputs. # This bus will route address bits to the decoder input and column mux inputs.
# The wires are actually routed after we placed the stuff on both sides. # The wires are actually routed after we placed the stuff on both sides.
# The predecoder is below the x-axis and the main decoder is above the x-axis # The predecoder is below the x-axis and the main decoder is above the x-axis
# The address flop and decoder are aligned in the x coord. # The address flop and decoder are aligned in the x coord.
for port in self.all_ports: for port in self.all_ports:
if port%2: if port % 2:
mirror = "MY" mirror = "MY"
else: else:
mirror = "R0" mirror = "R0"
self.port_address_inst[port].place(offset=offsets[port], mirror=mirror) self.port_address_inst[port].place(offset=offsets[port], mirror=mirror)
def create_column_decoder(self): def create_column_decoder(self):
""" """
Create a 2:4 or 3:8 column address decoder. Create a 2:4 or 3:8 column address decoder.
""" """
@ -510,40 +495,38 @@ class bank(design.design):
self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=self.dff.height) self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=self.dff.height)
else: else:
# No error checking before? # No error checking before?
debug.error("Invalid column decoder?",-1) debug.error("Invalid column decoder?", -1)
self.add_mod(self.column_decoder) self.add_mod(self.column_decoder)
self.column_decoder_inst = [None]*len(self.all_ports) self.column_decoder_inst = [None] * len(self.all_ports)
for port in self.all_ports: for port in self.all_ports:
self.column_decoder_inst[port] = self.add_inst(name="col_address_decoder{}".format(port), self.column_decoder_inst[port] = self.add_inst(name="col_address_decoder{}".format(port),
mod=self.column_decoder) mod=self.column_decoder)
temp = [] temp = []
for bit in range(self.col_addr_size): for bit in range(self.col_addr_size):
temp.append("addr{0}_{1}".format(port,bit)) temp.append("addr{0}_{1}".format(port, bit))
for bit in range(self.num_col_addr_lines): for bit in range(self.num_col_addr_lines):
temp.append("sel{0}_{1}".format(port,bit)) temp.append("sel{0}_{1}".format(port, bit))
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_column_decoder(self, offsets): def place_column_decoder(self, offsets):
""" """
Place a 2:4 or 3:8 column address decoder. Place a 2:4 or 3:8 column address decoder.
""" """
if self.col_addr_size == 0: if self.col_addr_size == 0:
return return
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place column decoder.") debug.check(len(offsets)>=len(self.all_ports),
"Insufficient offsets to place column decoder.")
for port in self.all_ports: for port in self.all_ports:
if port%2 == 1: if port % 2 == 1:
mirror = "XY" mirror = "XY"
else: else:
mirror = "R0" mirror = "R0"
self.column_decoder_inst[port].place(offset=offsets[port], mirror=mirror) self.column_decoder_inst[port].place(offset=offsets[port], mirror=mirror)
def create_bank_select(self): def create_bank_select(self):
""" Create the bank select logic. """ """ Create the bank select logic. """
@ -551,7 +534,7 @@ class bank(design.design):
if not self.num_banks > 1: if not self.num_banks > 1:
return return
self.bank_select_inst = [None]*len(self.all_ports) self.bank_select_inst = [None] * len(self.all_ports)
for port in self.all_ports: for port in self.all_ports:
self.bank_select_inst[port] = self.add_inst(name="bank_select{}".format(port), self.bank_select_inst[port] = self.add_inst(name="bank_select{}".format(port),
mod=self.bank_select) mod=self.bank_select)
@ -563,24 +546,23 @@ class bank(design.design):
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
def place_bank_select(self, offsets): def place_bank_select(self, offsets):
""" Place the bank select logic. """ """ Place the bank select logic. """
if not self.num_banks > 1: if not self.num_banks > 1:
return return
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place bank select logic.") debug.check(len(offsets)>=len(self.all_ports),
"Insufficient offsets to place bank select logic.")
for port in self.all_ports: for port in self.all_ports:
self.bank_select_inst[port].place(offsets[port]) self.bank_select_inst[port].place(offsets[port])
def route_supplies(self): def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ Propagate all vdd/gnd pins up to this level for all modules """
for inst in self.insts: for inst in self.insts:
self.copy_power_pins(inst,"vdd") self.copy_power_pins(inst, "vdd")
self.copy_power_pins(inst,"gnd") self.copy_power_pins(inst, "gnd")
def route_bank_select(self, port): def route_bank_select(self, port):
""" Route the bank select logic. """ """ Route the bank select logic. """
@ -595,7 +577,7 @@ class bank(design.design):
bank_sel_signals = ["clk_buf", "s_en", "p_en_bar", "bank_sel"] bank_sel_signals = ["clk_buf", "s_en", "p_en_bar", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_s_en", "gated_p_en_bar"] gated_bank_sel_signals = ["gated_clk_buf", "gated_s_en", "gated_p_en_bar"]
copy_control_signals = self.input_control_signals[port]+["bank_sel{}".format(port)] copy_control_signals = self.input_control_signals[port] + ["bank_sel{}".format(port)]
for signal in range(len(copy_control_signals)): for signal in range(len(copy_control_signals)):
self.copy_layout_pin(self.bank_select_inst[port], bank_sel_signals[signal], copy_control_signals[signal]) self.copy_layout_pin(self.bank_select_inst[port], bank_sel_signals[signal], copy_control_signals[signal])
@ -604,25 +586,24 @@ class bank(design.design):
out_pos = self.bank_select_inst[port].get_pin(gated_bank_sel_signals[signal]).rc() out_pos = self.bank_select_inst[port].get_pin(gated_bank_sel_signals[signal]).rc()
name = self.control_signals[port][signal] name = self.control_signals[port][signal]
bus_pos = vector(self.bus_xoffset[port][name].x, out_pos.y) bus_pos = vector(self.bus_xoffset[port][name].x, out_pos.y)
self.add_path("m3",[out_pos, bus_pos]) self.add_path("m3", [out_pos, bus_pos])
self.add_via_center(layers=self.m2_stack, self.add_via_center(layers=self.m2_stack,
offset=bus_pos) offset=bus_pos)
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,
offset=out_pos) offset=out_pos)
self.add_via_center(layers=self.m2_stack, self.add_via_center(layers=self.m2_stack,
offset=out_pos) offset=out_pos)
def setup_routing_constraints(self): def setup_routing_constraints(self):
""" """
After the modules are instantiated, find the dimensions for the After the modules are instantiated, find the dimensions for the
control bus, power ring, etc. control bus, power ring, etc.
""" """
self.max_y_offset = max([x.uy() for x in self.insts]) + 3*self.m1_width self.max_y_offset = max([x.uy() for x in self.insts]) + 3 * self.m1_width
self.min_y_offset = min([x.by() for x in self.insts]) self.min_y_offset = min([x.by() for x in self.insts])
self.max_x_offset = max([x.rx() for x in self.insts]) + 3*self.m1_width self.max_x_offset = max([x.rx() for x in self.insts]) + 3 * self.m1_width
self.min_x_offset = min([x.lx() for x in self.insts]) self.min_x_offset = min([x.lx() for x in self.insts])
# # Create the core bbox for the power rings # # Create the core bbox for the power rings
@ -632,7 +613,6 @@ class bank(design.design):
self.height = ur.y - ll.y self.height = ur.y - ll.y
self.width = ur.x - ll.x self.width = ur.x - ll.x
def route_central_bus(self): def route_central_bus(self):
""" Create the address, supply, and control signal central bus lines. """ """ Create the address, supply, and control signal central bus lines. """
@ -640,13 +620,13 @@ class bank(design.design):
# Overall central bus width. It includes all the column mux lines, # Overall central bus width. It includes all the column mux lines,
# and control lines. # and control lines.
self.bus_xoffset = [None]*len(self.all_ports) self.bus_xoffset = [None] * len(self.all_ports)
# Port 0 # Port 0
# The bank is at (0,0), so this is to the left of the y-axis. # The bank is at (0,0), so this is to the left of the y-axis.
# 2 pitches on the right for vias/jogs to access the inputs # 2 pitches on the right for vias/jogs to access the inputs
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines[0] - self.m2_pitch, self.min_y_offset) control_bus_offset = vector(-self.m2_pitch * self.num_control_lines[0] - self.m2_pitch, self.min_y_offset)
# The control bus is routed up to two pitches below the bitcell array # The control bus is routed up to two pitches below the bitcell array
control_bus_length = self.main_bitcell_array_bottom - self.min_y_offset - 2*self.m1_pitch control_bus_length = self.main_bitcell_array_bottom - self.min_y_offset - 2 * self.m1_pitch
self.bus_xoffset[0] = self.create_bus(layer="m2", self.bus_xoffset[0] = self.create_bus(layer="m2",
pitch=self.m2_pitch, pitch=self.m2_pitch,
offset=control_bus_offset, offset=control_bus_offset,
@ -658,7 +638,7 @@ class bank(design.design):
# Port 1 # Port 1
if len(self.all_ports)==2: if len(self.all_ports)==2:
# The other control bus is routed up to two pitches above the bitcell array # The other control bus is routed up to two pitches above the bitcell array
control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2*self.m1_pitch control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2 * self.m1_pitch
control_bus_offset = vector(self.bitcell_array_right + self.m2_pitch, control_bus_offset = vector(self.bitcell_array_right + self.m2_pitch,
self.max_y_offset - control_bus_length) self.max_y_offset - control_bus_length)
# The bus for the right port is reversed so that the rbl_wl is closest to the array # The bus for the right port is reversed so that the rbl_wl is closest to the array
@ -669,7 +649,6 @@ class bank(design.design):
length=control_bus_length, length=control_bus_length,
vertical=True, vertical=True,
make_pins=(self.num_banks==1)) make_pins=(self.num_banks==1))
def route_port_data_to_bitcell_array(self, port): def route_port_data_to_bitcell_array(self, port):
""" Routing of BL and BR between port data and bitcell array """ """ Routing of BL and BR between port data and bitcell array """
@ -677,11 +656,11 @@ class bank(design.design):
# Connect the regular bitlines # Connect the regular bitlines
inst2 = self.port_data_inst[port] inst2 = self.port_data_inst[port]
inst1 = self.bitcell_array_inst inst1 = self.bitcell_array_inst
inst1_bl_name = self.bl_names[port]+"_{}" inst1_bl_name = self.bl_names[port] + "_{}"
inst1_br_name = self.br_names[port]+"_{}" inst1_br_name = self.br_names[port] + "_{}"
inst2_bl_name = inst2.mod.get_bl_names()+"_{}" inst2_bl_name = inst2.mod.get_bl_names() + "_{}"
inst2_br_name = inst2.mod.get_br_names()+"_{}" inst2_br_name = inst2.mod.get_br_names() + "_{}"
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols, self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name,
@ -693,20 +672,17 @@ class bank(design.design):
self.connect_bitline(inst1, inst2, rbl_bl_name, "rbl_bl") self.connect_bitline(inst1, inst2, rbl_bl_name, "rbl_bl")
self.connect_bitline(inst1, inst2, rbl_br_name, "rbl_br") self.connect_bitline(inst1, inst2, rbl_br_name, "rbl_br")
def route_port_data_out(self, port): def route_port_data_out(self, port):
""" Add pins for the port data out """ """ Add pins for the port data out """
for bit in range(self.word_size): for bit in range(self.word_size):
data_pin = self.port_data_inst[port].get_pin("dout_{0}".format(bit)) data_pin = self.port_data_inst[port].get_pin("dout_{0}".format(bit))
self.add_layout_pin_rect_center(text="dout{0}_{1}".format(port,bit), self.add_layout_pin_rect_center(text="dout{0}_{1}".format(port, bit),
layer=data_pin.layer, layer=data_pin.layer,
offset=data_pin.center(), offset=data_pin.center(),
height=data_pin.height(), height=data_pin.height(),
width=data_pin.width()) width=data_pin.width())
def route_port_address_in(self, port): def route_port_address_in(self, port):
""" Routes the row decoder inputs and supplies """ """ Routes the row decoder inputs and supplies """
@ -714,17 +690,15 @@ class bank(design.design):
for row in range(self.row_addr_size): for row in range(self.row_addr_size):
addr_idx = row + self.col_addr_size addr_idx = row + self.col_addr_size
decoder_name = "addr_{}".format(row) decoder_name = "addr_{}".format(row)
addr_name = "addr{0}_{1}".format(port,addr_idx) addr_name = "addr{0}_{1}".format(port, addr_idx)
self.copy_layout_pin(self.port_address_inst[port], decoder_name, addr_name) self.copy_layout_pin(self.port_address_inst[port], decoder_name, addr_name)
def route_port_data_in(self, port): def route_port_data_in(self, port):
""" Connecting port data in """ """ Connecting port data in """
for row in range(self.word_size): for row in range(self.word_size):
data_name = "din_{}".format(row) data_name = "din_{}".format(row)
din_name = "din{0}_{1}".format(port,row) din_name = "din{0}_{1}".format(port, row)
self.copy_layout_pin(self.port_data_inst[port], data_name, din_name) self.copy_layout_pin(self.port_data_inst[port], data_name, din_name)
if self.word_size: if self.word_size:
@ -732,8 +706,6 @@ class bank(design.design):
wmask_name = "bank_wmask_{}".format(row) wmask_name = "bank_wmask_{}".format(row)
bank_wmask_name = "bank_wmask{0}_{1}".format(port, row) bank_wmask_name = "bank_wmask{0}_{1}".format(port, row)
self.copy_layout_pin(self.port_data_inst[port], wmask_name, bank_wmask_name) self.copy_layout_pin(self.port_data_inst[port], wmask_name, bank_wmask_name)
def channel_route_bitlines(self, inst1, inst2, num_bits, def channel_route_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_bl_name="bl_{}", inst1_br_name="br_{}",
@ -751,19 +723,18 @@ class bank(design.design):
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name) (bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name)
(top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name) (top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name)
# Channel route each mux separately since we don't minimize the number # Channel route each mux separately since we don't minimize the number
# of tracks in teh channel router yet. If we did, we could route all the bits at once! # of tracks in teh channel router yet. If we did, we could route all the bits at once!
offset = bottom_inst.ul() + vector(0,self.m1_pitch) offset = bottom_inst.ul() + vector(0, self.m1_pitch)
for bit in range(num_bits): for bit in range(num_bits):
bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit)), bottom_inst.get_pin(bottom_br_name.format(bit))] bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit)), bottom_inst.get_pin(bottom_br_name.format(bit))]
top_names = [top_inst.get_pin(top_bl_name.format(bit)), top_inst.get_pin(top_br_name.format(bit))] top_names = [top_inst.get_pin(top_bl_name.format(bit)), top_inst.get_pin(top_br_name.format(bit))]
route_map = list(zip(bottom_names, top_names)) route_map = list(zip(bottom_names, top_names))
self.create_horizontal_channel_route(route_map, offset, self.m1_stack) self.create_horizontal_channel_route(route_map, offset, self.m1_stack)
def connect_bitline(self, inst1, inst2, inst1_name, inst2_name): def connect_bitline(self, inst1, inst2, inst1_name, inst2_name):
""" """
Connect two pins of two modules. Connect two pins of two modules.
This assumes that they have sufficient space to create a jog This assumes that they have sufficient space to create a jog
in the middle between the two modules (if needed). in the middle between the two modules (if needed).
""" """
@ -784,11 +755,13 @@ class bank(design.design):
bottom_loc = bottom_pin.uc() bottom_loc = bottom_pin.uc()
top_loc = top_pin.bc() top_loc = top_pin.bc()
yoffset = 0.5*(top_loc.y+bottom_loc.y) yoffset = 0.5 * (top_loc.y + bottom_loc.y)
self.add_path(top_pin.layer,[bottom_loc, vector(bottom_loc.x,yoffset), self.add_path(top_pin.layer,
vector(top_loc.x,yoffset), top_loc]) [bottom_loc,
vector(bottom_loc.x, yoffset),
vector(top_loc.x, yoffset),
top_loc])
def connect_bitlines(self, inst1, inst2, num_bits, def connect_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name, inst1_br_name, inst1_bl_name, inst1_br_name,
inst2_bl_name, inst2_br_name): inst2_bl_name, inst2_br_name):
@ -799,14 +772,13 @@ class bank(design.design):
for col in range(num_bits): for col in range(num_bits):
self.connect_bitline(inst1, inst2, inst1_bl_name.format(col), inst2_bl_name.format(col)) self.connect_bitline(inst1, inst2, inst1_bl_name.format(col), inst2_bl_name.format(col))
self.connect_bitline(inst1, inst2, inst1_br_name.format(col), inst2_br_name.format(col)) self.connect_bitline(inst1, inst2, inst1_br_name.format(col), inst2_br_name.format(col))
def route_port_address(self, port): def route_port_address(self, port):
""" Connect Wordline driver to bitcell array wordline """ """ Connect Wordline driver to bitcell array wordline """
self.route_port_address_in(port) self.route_port_address_in(port)
if port%2: if port % 2:
self.route_port_address_right(port) self.route_port_address_right(port)
else: else:
self.route_port_address_left(port) self.route_port_address_left(port)
@ -817,21 +789,20 @@ class bank(design.design):
for row in range(self.num_rows): for row in range(self.num_rows):
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).rc() driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).rc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row)).lc()
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0) mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].rx() + 0.5 * self.bitcell_array_inst.lx(), 0)
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1) mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0.5, 1)
self.add_path("m1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path("m1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_port_address_right(self, port): def route_port_address_right(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """ """ Connecting Wordline driver output to Bitcell WL connection """
for row in range(self.num_rows): for row in range(self.num_rows):
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).lc() driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).lc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row)).rc()
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0) mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].lx() + 0.5 * self.bitcell_array_inst.rx(), 0)
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1) mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0, 1)
self.add_path("m1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path("m1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_column_address_lines(self, port): def route_column_address_lines(self, port):
@ -845,7 +816,7 @@ class bank(design.design):
decode_names = ["Zb", "Z"] decode_names = ["Zb", "Z"]
# The Address LSB # The Address LSB
self.copy_layout_pin(self.column_decoder_inst[port], "A", "addr{}_0".format(port)) self.copy_layout_pin(self.column_decoder_inst[port], "A", "addr{}_0".format(port))
elif self.col_addr_size > 1: elif self.col_addr_size > 1:
decode_names = [] decode_names = []
@ -854,11 +825,11 @@ class bank(design.design):
for i in range(self.col_addr_size): for i in range(self.col_addr_size):
decoder_name = "in_{}".format(i) decoder_name = "in_{}".format(i)
addr_name = "addr{0}_{1}".format(port,i) addr_name = "addr{0}_{1}".format(port, i)
self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name) self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name)
if port%2: if port % 2:
offset = self.column_decoder_inst[port].ll() - vector(self.num_col_addr_lines*self.m2_pitch, 0) offset = self.column_decoder_inst[port].ll() - vector(self.num_col_addr_lines * self.m2_pitch, 0)
else: else:
offset = self.column_decoder_inst[port].lr() + vector(self.m2_pitch, 0) offset = self.column_decoder_inst[port].lr() + vector(self.m2_pitch, 0)
@ -871,7 +842,8 @@ class bank(design.design):
self.create_vertical_channel_route(route_map, offset, self.m1_stack) self.create_vertical_channel_route(route_map, offset, self.m1_stack)
def add_lvs_correspondence_points(self): def add_lvs_correspondence_points(self):
""" This adds some points for easier debugging if LVS goes wrong. """
This adds some points for easier debugging if LVS goes wrong.
These should probably be turned off by default though, since extraction These should probably be turned off by default though, since extraction
will show these as ports in the extracted netlist. will show these as ports in the extracted netlist.
""" """
@ -880,7 +852,7 @@ class bank(design.design):
wl_name = "wl_{}".format(i) wl_name = "wl_{}".format(i)
wl_pin = self.bitcell_array_inst.get_pin(wl_name) wl_pin = self.bitcell_array_inst.get_pin(wl_name)
self.add_label(text=wl_name, self.add_label(text=wl_name,
layer="m1", layer="m1",
offset=wl_pin.center()) offset=wl_pin.center())
# Add the bitline names # Add the bitline names
@ -890,35 +862,35 @@ class bank(design.design):
bl_pin = self.bitcell_array_inst.get_pin(bl_name) bl_pin = self.bitcell_array_inst.get_pin(bl_name)
br_pin = self.bitcell_array_inst.get_pin(br_name) br_pin = self.bitcell_array_inst.get_pin(br_name)
self.add_label(text=bl_name, self.add_label(text=bl_name,
layer="m2", layer="m2",
offset=bl_pin.center()) offset=bl_pin.center())
self.add_label(text=br_name, self.add_label(text=br_name,
layer="m2", layer="m2",
offset=br_pin.center()) offset=br_pin.center())
# # Add the data output names to the sense amp output # # Add the data output names to the sense amp output
# for i in range(self.word_size): # for i in range(self.word_size):
# data_name = "data_{}".format(i) # data_name = "data_{}".format(i)
# data_pin = self.sense_amp_array_inst.get_pin(data_name) # data_pin = self.sense_amp_array_inst.get_pin(data_name)
# self.add_label(text="sa_out_{}".format(i), # self.add_label(text="sa_out_{}".format(i),
# layer="m2", # layer="m2",
# offset=data_pin.center()) # offset=data_pin.center())
# Add labels on the decoder # Add labels on the decoder
for port in self.write_ports: for port in self.write_ports:
for i in range(self.word_size): for i in range(self.word_size):
data_name = "dec_out_{}".format(i) data_name = "dec_out_{}".format(i)
pin_name = "in_{}".format(i) pin_name = "in_{}".format(i)
data_pin = self.wordline_driver_inst[port].get_pin(pin_name) data_pin = self.wordline_driver_inst[port].get_pin(pin_name)
self.add_label(text=data_name, self.add_label(text=data_name,
layer="m1", layer="m1",
offset=data_pin.center()) offset=data_pin.center())
def route_control_lines(self, port): def route_control_lines(self, port):
""" Route the control lines of the entire bank """ """ Route the control lines of the entire bank """
# Make a list of tuples that we will connect. # Make a list of tuples that we will connect.
# From control signal to the module pin # From control signal to the module pin
# Connection from the central bus to the main control block crosses # Connection from the central bus to the main control block crosses
# pre-decoder and this connection is in metal3 # pre-decoder and this connection is in metal3
connection = [] connection = []
@ -943,58 +915,59 @@ class bank(design.design):
for (control_signal, pin_pos) in connection: for (control_signal, pin_pos) in connection:
control_mid_pos = self.bus_xoffset[port][control_signal] control_mid_pos = self.bus_xoffset[port][control_signal]
control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y) control_pos = vector(self.bus_xoffset[port][control_signal].x, pin_pos.y)
self.add_wire(self.m1_stack, [control_mid_pos, control_pos, pin_pos]) self.add_wire(self.m1_stack, [control_mid_pos, control_pos, pin_pos])
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,
offset=control_pos) offset=control_pos)
# clk to wordline_driver # clk to wordline_driver
control_signal = self.prefix+"wl_en{}".format(port) control_signal = self.prefix + "wl_en{}".format(port)
if port%2: if port % 2:
pin_pos = self.port_address_inst[port].get_pin("wl_en").uc() pin_pos = self.port_address_inst[port].get_pin("wl_en").uc()
mid_pos = pin_pos + vector(0,2*self.m2_gap) # to route down to the top of the bus mid_pos = pin_pos + vector(0, 2 * self.m2_gap) # to route down to the top of the bus
else: else:
pin_pos = self.port_address_inst[port].get_pin("wl_en").bc() pin_pos = self.port_address_inst[port].get_pin("wl_en").bc()
mid_pos = pin_pos - vector(0,2*self.m2_gap) # to route down to the top of the bus mid_pos = pin_pos - vector(0, 2 * self.m2_gap) # to route down to the top of the bus
control_x_offset = self.bus_xoffset[port][control_signal].x control_x_offset = self.bus_xoffset[port][control_signal].x
control_pos = vector(control_x_offset, mid_pos.y) control_pos = vector(control_x_offset, mid_pos.y)
self.add_wire(self.m1_stack,[pin_pos, mid_pos, control_pos]) self.add_wire(self.m1_stack, [pin_pos, mid_pos, control_pos])
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,
offset=control_pos) offset=control_pos)
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True): def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
"""Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline""" """Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline"""
#Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption # Decoder is assumed to have settled before the negative edge of the clock.
# Delay model relies on this assumption
stage_effort_list = [] stage_effort_list = []
wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout
stage_effort_list += self.port_address.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise) stage_effort_list += self.port_address.wordline_driver.determine_wordline_stage_efforts(wordline_cout,
inp_is_rise)
return stage_effort_list return stage_effort_list
def get_wl_en_cin(self): def get_wl_en_cin(self):
"""Get the relative capacitance of all the clk connections in the bank""" """Get the relative capacitance of all the clk connections in the bank"""
#wl_en only used in the wordline driver. # wl_en only used in the wordline driver.
return self.port_address.wordline_driver.get_wl_en_cin() return self.port_address.wordline_driver.get_wl_en_cin()
def get_w_en_cin(self): def get_w_en_cin(self):
"""Get the relative capacitance of all the clk connections in the bank""" """Get the relative capacitance of all the clk connections in the bank"""
#wl_en only used in the wordline driver. # wl_en only used in the wordline driver.
port = self.write_ports[0] port = self.write_ports[0]
return self.port_data[port].write_driver.get_w_en_cin() return self.port_data[port].write_driver.get_w_en_cin()
def get_clk_bar_cin(self): def get_clk_bar_cin(self):
"""Get the relative capacitance of all the clk_bar connections in the bank""" """Get the relative capacitance of all the clk_bar connections in the bank"""
#Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array. # Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array.
#Precharges are the all the same in Mulitport, one is picked # Precharges are the all the same in Mulitport, one is picked
port = self.read_ports[0] port = self.read_ports[0]
return self.port_data[port].precharge_array.get_en_cin() return self.port_data[port].precharge_array.get_en_cin()
def get_sen_cin(self): def get_sen_cin(self):
"""Get the relative capacitance of all the sense amp enable connections in the bank""" """Get the relative capacitance of all the sense amp enable connections in the bank"""
#Current bank only uses sen as an enable for the sense amps. # Current bank only uses sen as an enable for the sense amps.
port = self.read_ports[0] port = self.read_ports[0]
return self.port_data[port].sense_amp_array.get_en_cin() return self.port_data[port].sense_amp_array.get_en_cin()
def graph_exclude_precharge(self): def graph_exclude_precharge(self):
@ -1005,5 +978,7 @@ class bank(design.design):
def get_cell_name(self, inst_name, row, col): def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell.""" """Gets the spice name of the target bitcell."""
return self.bitcell_array_inst.mod.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col) return self.bitcell_array_inst.mod.get_cell_name(inst_name + '.x' + self.bitcell_array_inst.name,
row,
col)