Connect bank supply rings in sram.py.

This commit is contained in:
Matt Guthaus 2018-03-05 13:49:22 -08:00
parent 0c203c1c7e
commit 4205a6a700
3 changed files with 270 additions and 328 deletions

View File

@ -21,7 +21,8 @@ class bank(design.design):
mod_list = ["tri_gate", "bitcell", "decoder", "ms_flop_array", "wordline_driver",
"bitcell_array", "sense_amp_array", "precharge_array",
"column_mux_array", "write_driver_array", "tri_gate_array"]
"column_mux_array", "write_driver_array", "tri_gate_array",
"bank_select"]
for mod_name in mod_list:
config_mod_name = getattr(OPTS, mod_name)
class_file = reload(__import__(config_mod_name))
@ -50,11 +51,13 @@ class bank(design.design):
self.create_modules()
self.add_modules()
self.setup_layout_constraints()
self.route_power_ring(self.core_bbox)
if self.num_banks > 1:
self.add_bank_select()
self.route_layout()
# Add and route the bank select logic
if(self.num_banks > 1):
self.add_bank_select()
# Can remove the following, but it helps for debug!
self.add_lvs_correspondence_points()
@ -72,7 +75,7 @@ class bank(design.design):
# For more than one bank, we have a bank select and name
# the signals gated_*.
if(self.num_banks > 1):
if self.num_banks > 1:
self.add_pin("bank_sel")
for pin in ["s_en","w_en","tri_en_bar","tri_en",
"clk_bar","clk_buf","vdd","gnd"]:
@ -80,7 +83,6 @@ class bank(design.design):
def route_layout(self):
""" Create routing amoung the modules """
self.route_power_ring(self.core_bbox)
self.create_central_bus()
self.route_precharge_to_bitcell_array()
self.route_sense_amp_to_trigate()
@ -91,6 +93,9 @@ class bank(design.design):
self.route_msf_address()
self.route_control_lines()
self.add_control_pins()
if self.num_banks > 1:
self.route_bank_select()
self.route_vdd_supply()
self.route_gnd_supply()
@ -108,7 +113,7 @@ class bank(design.design):
self.column_mux_height = 0
if self.col_addr_size > 1: # size 1 is from addr FF
self.add_column_decoder()
self.add_sense_amp_array()
self.add_write_driver_array()
self.add_msf_data_in()
@ -139,7 +144,7 @@ class bank(design.design):
# The order of the control signals on the control bus:
self.input_control_signals = ["clk_buf", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"]
# These will be outputs of the gaters if this is multibank
if self.num_banks>1:
if self.num_banks > 1:
self.control_signals = ["gated_"+str for str in self.input_control_signals]
else:
self.control_signals = self.input_control_signals
@ -177,7 +182,7 @@ class bank(design.design):
self.precharge_array = self.mod_precharge_array(columns=self.num_cols)
self.add_mod(self.precharge_array)
if(self.col_addr_size > 0):
if self.col_addr_size > 0:
self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.column_mux_array)
@ -213,6 +218,10 @@ class bank(design.design):
self.inv = pinv()
self.add_mod(self.inv)
if(self.num_banks > 1):
self.bank_select = self.mod_bank_select()
self.add_mod(self.bank_select)
def add_bitcell_array(self):
@ -452,133 +461,37 @@ class bank(design.design):
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def add_bank_select(self):
"""Create a bank select signal that is combined with an array of
NOR+INV gates to gate the control signals in case of multiple
banks are created in upper level SRAM module
"""
""" Instantiate the bank select logic. """
xoffset = self.left_vdd_x_offset + self.supply_rail_pitch
# extra space to allow vias
yoffset = self.min_point + 2*self.supply_rail_pitch + self.m1_space
self.bank_select_pos = vector(xoffset,yoffset)
self.bank_select_inst = self.add_inst(name="bank_select",
mod=self.bank_select,
offset=self.bank_select_pos)
# 4x Inverter
self.inv4x = pinv(4)
self.add_mod(self.inv4x)
self.nor2 = pnor2()
self.add_mod(self.nor2)
self.nand2 = pnand2()
self.add_mod(self.nand2)
# left of gnd rail is the "bus start"
bus_start = self.start_of_right_central_bus - self.m2_space
xoffset_nand = bus_start - self.nand2.width - self.inv4x.width - drc["pwell_to_nwell"]
xoffset_nor = bus_start - self.nor2.width - self.inv4x.width - drc["pwell_to_nwell"]
xoffset_inv = bus_start - self.inv4x.width
xoffset_bank_sel_inv = xoffset_nor - self.inv.width - 3*self.m2_pitch
xoffset_inputs = xoffset_bank_sel_inv - 6*self.m2_pitch
# bank select inverter
self.bank_select_inv_position = vector(xoffset_bank_sel_inv,
self.min_point)
# bank select inverter (must be made unique if more than one OR)
bank_sel_inv=self.add_inst(name="bank_sel_inv",
mod=self.inv,
offset=[xoffset_bank_sel_inv,self.min_point])
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
# bank_sel is vertical wire
bank_sel_inv_pin = bank_sel_inv.get_pin("A")
xoffset_bank_sel = bank_sel_inv_pin.lx()
bank_sel_line_pos = vector(xoffset_bank_sel, self.min_point)
bank_sel_line_end = vector(xoffset_bank_sel, self.decoder_min_point-self.m2_pitch)
self.add_path("metal2", [bank_sel_line_pos,bank_sel_line_end])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=bank_sel_inv_pin.lc())
# Route the pin to the left edge as well
bank_sel_pin_pos=vector(self.left_vdd_x_offset, self.min_point)
bank_sel_pin_end=vector(bank_sel_line_pos.x, bank_sel_pin_pos.y)
self.add_layout_pin_center_segment(text="bank_sel",
layer="metal3",
start=bank_sel_pin_pos,
end=bank_sel_pin_end)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=bank_sel_pin_end,
rotate=90)
# bank_sel_bar is vertical wire
bank_sel_bar_pin = bank_sel_inv.get_pin("Z")
xoffset_bank_sel_bar = bank_sel_bar_pin.rx()
self.add_label_pin(text="bank_sel_bar",
layer="metal2",
offset=vector(xoffset_bank_sel_bar, self.min_point),
height=2*self.inv.height)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=bank_sel_bar_pin.rc())
temp = []
for i in range(self.num_control_lines):
input_name = self.input_control_signals[i]
gated_name = self.control_signals[i]
name_nand = "nand_{}".format(input_name)
name_nor = "nor_{}".format(input_name)
name_inv = "inv_{}".format(input_name)
temp.append(self.input_control_signals[i])
for i in range(self.num_control_lines):
temp.append(self.control_signals[i])
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
y_offset = self.min_point + self.inv.height * i
if i%2:
y_offset += self.inv.height
mirror = "MX"
else:
mirror = ""
# These require OR (nor2+inv) gates since they are active low.
# (writes occur on clk low)
if input_name in ("clk_buf", "tri_en_bar"):
logic_inst=self.add_inst(name=name_nor,
mod=self.nor2,
offset=[xoffset_nor, y_offset],
mirror=mirror)
self.connect_inst([input_name,
"bank_sel_bar",
gated_name+"_temp_bar",
"vdd",
"gnd"])
xoffset_bank_signal = xoffset_bank_sel_bar
# the rest are AND (nand2+inv) gates
else:
logic_inst=self.add_inst(name=name_nand,
mod=self.nand2,
offset=[xoffset_nand, y_offset],
mirror=mirror)
bank_sel_signal = "bank_sel"
self.connect_inst([input_name,
"bank_sel",
gated_name+"_temp_bar",
"vdd",
"gnd"])
xoffset_bank_signal = xoffset_bank_sel
# They all get inverters on the output
inv_inst=self.add_inst(name=name_inv,
mod=self.inv4x,
offset=[xoffset_inv, y_offset],
mirror=mirror)
self.connect_inst([gated_name+"_temp_bar",
gated_name,
"vdd",
"gnd"])
# Connect the logic output to inverter input
pre = logic_inst.get_pin("Z").lc()
out_position = logic_inst.get_pin("Z").rc() + vector(0.5*self.m1_width,0)
in_position = inv_inst.get_pin("A").lc() + vector(0.5*self.m1_width,0)
post = inv_inst.get_pin("A").rc()
self.add_path("metal1", [pre, out_position, in_position, post])
def route_bank_select(self):
""" Route the bank select logic. """
for input_name in self.input_control_signals+["bank_sel"]:
in_pos = self.bank_select_inst.get_pin(input_name).lc()
self.add_layout_pin_center_segment(text=input_name,
layer="metal3",
start=vector(self.left_gnd_x_offset,in_pos.y),
end=in_pos)
for gated_name in self.control_signals:
# Connect the inverter output to the central bus
out_pos = inv_inst.get_pin("Z").rc()
out_pos = self.bank_select_inst.get_pin(gated_name).rc()
bus_pos = vector(self.central_line_xoffset[gated_name], out_pos.y)
self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"),
@ -590,50 +503,7 @@ class bank(design.design):
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=out_pos,
rotate=90)
# Connect the logic B input to bank_sel/bank_sel_bar
logic_pos = logic_inst.get_pin("B").lc() - vector(0.5*contact.m1m2.height,0)
input_pos = vector(xoffset_bank_signal,logic_pos.y)
self.add_path("metal2",[logic_pos, input_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos,
rotate=90)
# Connect the logic A input to the input pin
logic_pos = logic_inst.get_pin("A").lc()
input_pos = vector(self.left_vdd_x_offset,logic_pos.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos,
rotate=90)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=logic_pos,
rotate=90)
self.add_layout_pin_center_segment(text=input_name,
layer="metal3",
start=input_pos,
end=logic_pos)
# Add vdd/gnd supply rails
gnd_pin = inv_inst.get_pin("gnd")
left_gnd_pos = vector(self.left_gnd_x_center, gnd_pos.cy())
self.add_path("metal1",[left_gnd_pos, gnd_pos.rc()])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_gnd_pos,
size = (1,3),
rotate=90)
vdd_pin = inv_inst.get_pin("vdd")
left_vdd_pos = vector(self.left_vdd_x_center, vdd_pin.cy())
self.add_path("metal1",[left_vdd_pos, vdd_pin.rc()])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_vdd_pos,
size = (1,3),
rotate=90)
def setup_layout_constraints(self):
""" Calculating layout constraints, width, height etc """
@ -653,7 +523,7 @@ class bank(design.design):
if self.num_banks>1:
# The control gating logic is below the decoder
# Min of the control gating logic and tri gate.
self.min_point = min(self.decoder_min_point - self.num_control_lines * self.bitcell.height, tri_gate_min_point)
self.min_point = min(self.decoder_min_point - self.bank_select.height, tri_gate_min_point)
else:
# Just the min of the decoder logic logic and tri gate.
self.min_point = min(self.decoder_min_point, addr_min_point, tri_gate_min_point)
@ -961,30 +831,6 @@ class bank(design.design):
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
# route the gnd rails, add contact to rail as well
for gnd_pin in self.wordline_driver_inst.get_pins("gnd"):
gnd_pos = gnd_pin.rc()
left_rail_pos = vector(self.left_gnd_x_center, gnd_pos.y)
self.add_path("metal1", [left_rail_pos, gnd_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_rail_pos,
size = (1,3),
rotate=90)
# route the vdd rails
for vdd_pin in self.wordline_driver_inst.get_pins("vdd"):
vdd_pos = vdd_pin.rc()
left_rail_pos = vector(self.left_vdd_x_center, vdd_pos.y)
right_rail_pos = vector(self.right_vdd_x_center, vdd_pos.y)
self.add_path("metal1", [left_rail_pos, right_rail_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_rail_pos,
size = (1,3),
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=right_rail_pos,
size = (1,3),
rotate=90)
@ -1237,9 +1083,11 @@ class bank(design.design):
def route_vdd_supply(self):
""" Route vdd for the precharge, sense amp, write_driver, data FF, tristate """
for inst in [self.precharge_array_inst, self.sense_amp_array_inst,
self.write_driver_array_inst, self.msf_data_in_inst,
self.tri_gate_array_inst]:
# Route the vdd rails to the RIGHT
modules = [self.precharge_array_inst, self.sense_amp_array_inst,
self.write_driver_array_inst, self.msf_data_in_inst,
self.tri_gate_array_inst]
for inst in modules:
for vdd_pin in inst.get_pins("vdd"):
self.add_rect(layer="metal1",
offset=vdd_pin.ll(),
@ -1250,12 +1098,39 @@ class bank(design.design):
offset=via_position,
size = (1,3),
rotate=90)
# Route the vdd rails to the LEFT
for vdd_pin in self.wordline_driver_inst.get_pins("vdd"):
vdd_pos = vdd_pin.rc()
left_rail_pos = vector(self.left_vdd_x_center, vdd_pos.y)
right_rail_pos = vector(self.right_vdd_x_center, vdd_pos.y)
self.add_path("metal1", [left_rail_pos, right_rail_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_rail_pos,
size = (1,3),
rotate=90)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=right_rail_pos,
size = (1,3),
rotate=90)
if self.num_banks>1:
for vdd_pin in self.bank_select_inst.get_pins("vdd"):
vdd_pos = vdd_pin.rc()
left_rail_pos = vector(self.left_vdd_x_center, vdd_pos.y)
self.add_path("metal1", [left_rail_pos, vdd_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_rail_pos,
size = (1,3),
rotate=90)
def route_gnd_supply(self):
""" Route gnd for the precharge, sense amp, write_driver, data FF, tristate """
""" Route gnd rails"""
# Route the gnd rails to the RIGHT
# precharge is connected by abutment
for inst in [ self.tri_gate_array_inst, self.sense_amp_array_inst, self.msf_data_in_inst, self.write_driver_array_inst]:
modules = [ self.tri_gate_array_inst, self.sense_amp_array_inst, self.msf_data_in_inst, self.write_driver_array_inst]
for inst in modules:
for gnd_pin in inst.get_pins("gnd"):
if gnd_pin.layer != "metal1":
continue
@ -1269,6 +1144,20 @@ class bank(design.design):
size = (1,3),
rotate=90)
# Route the gnd rails to the LEFT
modules = [self.wordline_driver_inst]
if self.num_banks>1:
modules.append(self.bank_select_inst)
for inst in modules:
for gnd_pin in inst.get_pins("gnd"):
gnd_pos = gnd_pin.rc()
left_rail_pos = vector(self.left_gnd_x_center, gnd_pos.y)
self.add_path("metal1", [left_rail_pos, gnd_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=left_rail_pos,
size = (1,3),
rotate=90)
def add_control_pins(self):
""" Add the control signal input pins """

View File

@ -31,6 +31,8 @@ class bank_select(design.design):
for i in range(self.num_control_lines):
gated_name = self.control_signals[i]
self.add_pin(gated_name)
self.add_pin("vdd")
self.add_pin("gnd")
self.create_modules()
self.calculate_module_offsets()
@ -61,26 +63,26 @@ class bank_select(design.design):
self.m1_pitch = contact.m1m2.height + max(self.m1_space,self.m2_space)
self.m2_pitch = contact.m2m3.height + max(self.m2_space,self.m3_space)
# left of gnd rail is the "bus start"
self.xoffset_nand = self.inv4x.width + 2*self.m2_pitch + drc["pwell_to_nwell"]
self.xoffset_nor = self.inv4x.width + 2*self.m2_pitch + drc["pwell_to_nwell"]
self.xoffset_inv = max(self.xoffset_nand + self.nand2.width, self.xoffset_nor + self.nor2.width)
self.xoffset_bank_sel_inv = 0
self.xoffset_inputs = 0
# Above the bottom rails (plus a pitch to allow vias)
self.yoffset_minpoint = self.m1_pitch
self.yoffset_maxpoint = self.num_control_lines * self.inv.height
# Include the M1 pitches for the supply rails and spacing
self.height = self.yoffset_maxpoint + 2*self.m1_pitch
self.width = self.xoffset_inv + self.inv4x.width
def add_modules(self):
# bank select inverter
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv,
self.yoffset_minpoint)
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0)
# bank select inverter (must be made unique if more than one OR)
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
mod=self.inv,
offset=[self.xoffset_bank_sel_inv, self.yoffset_minpoint])
offset=[self.xoffset_bank_sel_inv, 0])
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
self.logic_inst = []
@ -92,7 +94,7 @@ class bank_select(design.design):
name_nor = "nor_{}".format(input_name)
name_inv = "inv_{}".format(input_name)
y_offset = self.yoffset_minpoint + self.inv.height * i
y_offset = self.inv.height * i
if i%2:
y_offset += self.inv.height
mirror = "MX"
@ -143,14 +145,14 @@ class bank_select(design.design):
# bank_sel is vertical wire
bank_sel_inv_pin = self.bank_sel_inv.get_pin("A")
xoffset_bank_sel = bank_sel_inv_pin.lx()
bank_sel_line_pos = vector(xoffset_bank_sel, self.yoffset_minpoint)
bank_sel_line_pos = vector(xoffset_bank_sel, 0)
bank_sel_line_end = vector(xoffset_bank_sel, self.yoffset_maxpoint)
self.add_path("metal2", [bank_sel_line_pos, bank_sel_line_end])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=bank_sel_inv_pin.lc())
# Route the pin to the left edge as well
bank_sel_pin_pos=vector(0, self.yoffset_minpoint)
bank_sel_pin_pos=vector(0, 0)
bank_sel_pin_end=vector(bank_sel_line_pos.x, bank_sel_pin_pos.y)
self.add_layout_pin_center_segment(text="bank_sel",
layer="metal3",
@ -165,7 +167,7 @@ class bank_select(design.design):
xoffset_bank_sel_bar = bank_sel_bar_pin.rx()
self.add_label_pin(text="bank_sel_bar",
layer="metal2",
offset=vector(xoffset_bank_sel_bar, self.yoffset_minpoint),
offset=vector(xoffset_bank_sel_bar, 0),
height=2*self.inv.height)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=bank_sel_bar_pin.rc())

View File

@ -68,7 +68,7 @@ class sram(design.design):
# Can remove the following, but it helps for debug!
self.add_lvs_correspondence_points()
self.offset_all_coordinates()
#self.offset_all_coordinates()
sizes = self.find_highest_coords()
self.width = sizes[0]
self.height = sizes[1]
@ -175,10 +175,12 @@ class sram(design.design):
def add_four_bank_modules(self):
""" Adds the modules and the buses to the top level """
self.compute_four_bank_offsets()
self.compute_bus_sizes()
self.add_four_banks()
self.compute_four_bank_offsets()
self.add_busses()
self.add_four_bank_logic()
@ -190,10 +192,12 @@ class sram(design.design):
def add_two_bank_modules(self):
""" Adds the modules and the buses to the top level """
self.compute_two_bank_offsets()
self.compute_bus_sizes()
self.add_two_banks()
self.compute_two_bank_offsets()
self.add_busses()
self.add_two_bank_logic()
@ -233,7 +237,6 @@ class sram(design.design):
self.add_path("metal3",[pin_pos,rail_pos])
self.add_via_center(("metal2","via2","metal3"),rail_pos)
def route_four_banks(self):
""" Route all of the signals for the four bank SRAM. """
@ -274,7 +277,7 @@ class sram(design.design):
self.add_via_center(("metal2","via2","metal3"),rail_pos)
self.route_bank_supply_rails(bottom_banks=[2,3])
self.route_bank_supply_rails(left_banks=[0,2], bottom_banks=[2,3])
@ -310,16 +313,14 @@ class sram(design.design):
# The main difference is that the four bank SRAM has the data bus in the middle of the four banks
# as opposed to the top of the banks.
self.compute_bus_sizes()
# In 4 bank SRAM, the height is determined by the bank decoder and address flop
self.vertical_bus_height = 2*self.bank.height + 4*self.bank_to_bus_distance + self.data_bus_height \
+ self.supply_bus_height + self.msb_decoder.height + self.msb_address.width
# The address bus extends down through the power rails, but control and bank_sel bus don't
self.addr_bus_height = self.vertical_bus_height + 2*self.power_rail_pitch
self.addr_bus_height = self.vertical_bus_height
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 2*self.power_rail_pitch)
self.data_bus_offset = vector(0, 2*self.power_rail_pitch + self.bank.height + self.bank_to_bus_distance)
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 0)
self.data_bus_offset = vector(0, self.bank.height + self.bank_to_bus_distance)
self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height + self.bank.height + 2*self.bank_to_bus_distance)
self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height)
self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0)
@ -330,7 +331,7 @@ class sram(design.design):
# Bank select flops get put to the right of control logic above bank1 and the buses
# Leave a pitch to get the vdd rails up to M2
self.msb_address_position = vector(max(self.bank.width + self.vertical_bus_width + 2*self.bank_to_bus_distance, self.control_logic.width),
self.msb_address_position = vector(self.bank_inst[1].lx() + 3*self.supply_rail_pitch,
self.supply_bus_offset.y + self.supply_bus_height + 2*self.m1_pitch + self.msb_address.width)
# Decoder goes above the MSB address flops, and is flipped in Y
@ -341,15 +342,13 @@ class sram(design.design):
def compute_two_bank_offsets(self):
""" Compute the overall offsets for a two bank SRAM """
self.compute_bus_sizes()
# In 2 bank SRAM, the height is determined by the control bus which is higher than the msb address
self.vertical_bus_height = self.bank.height + 2*self.bank_to_bus_distance + self.data_bus_height + self.control_bus_height
# The address bus extends down through the power rails, but control and bank_sel bus don't
self.addr_bus_height = self.vertical_bus_height + 2*self.power_rail_pitch
self.addr_bus_height = self.vertical_bus_height
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 2*self.power_rail_pitch)
self.data_bus_offset = vector(0, 2*self.power_rail_pitch + self.bank.height + self.bank_to_bus_distance)
self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 0)
self.data_bus_offset = vector(0, self.bank.height + self.bank_to_bus_distance)
self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height)
self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height)
self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0)
@ -360,7 +359,7 @@ class sram(design.design):
# Bank select flops get put to the right of control logic above bank1 and the buses
# Leave a pitch to get the vdd rails up to M2
self.msb_address_position = vector(max(self.bank.width + self.vertical_bus_width + 2*self.bank_to_bus_distance,self.control_logic.width),
self.msb_address_position = vector(self.bank_inst[1].lx() + 3*self.supply_rail_pitch,
self.supply_bus_offset.y+self.supply_bus_height + 2*self.m1_pitch + self.msb_address.width)
def add_busses(self):
@ -419,7 +418,7 @@ class sram(design.design):
pitch=self.m1_pitch,
offset=self.supply_bus_offset+vector(0,self.m1_pitch),
names=["gnd"],
length=self.supply_bus_width-2*self.power_rail_width,
length=self.supply_bus_width,
vertical=False))
self.horz_control_bus_positions.update(self.create_bus(layer="metal1",
pitch=self.m1_pitch,
@ -497,13 +496,11 @@ class sram(design.design):
self.add_via_center(("metal2","via2","metal3"),rail_pos)
self.route_bank_supply_rails(bottom_banks=[0,1])
self.route_bank_supply_rails(left_banks=[0], bottom_banks=[0,1])
def route_double_msb_address(self):
""" Route two MSB address bits and the bank decoder for 4-bank SRAM """
# connect the MSB flops to the address input bus
for i in [0,1]:
@ -551,68 +548,107 @@ class sram(design.design):
self.add_wire(("metal1","via1","metal2"),[msb_pin_pos,out_pos,up_pos,in_pos])
self.add_via_center(("metal1","via1","metal2"),in_pos)
self.add_via_center(("metal1","via1","metal2"),msb_pin_pos,rotate=90)
self.route_double_msb_address_supplies()
def route_double_msb_address_supplies(self):
""" Route the vdd/gnd bits of the 2-bit bank decoder. """
# Route the right-most vdd/gnd of the right upper bank to the top of the decoder
vdd_pins = self.bank_inst[1].get_pins("vdd")
highest_x = None
for bank_vdd_pin in vdd_pins:
if highest_x == None or bank_vdd_pin.lx()>highest_x:
highest_x = bank_vdd_pin.lx()
bank_vdd_pos = bank_vdd_pin.ul()
# Route to top
self.add_rect(layer="metal1",
offset=bank_vdd_pos,
height=self.height-bank_vdd_pos.y,
width=bank_vdd_pin.width())
left_bank_vdd_pin = None
right_bank_vdd_pin = None
for vdd_pin in vdd_pins:
if vdd_pin.layer != "metal2":
continue
if left_bank_vdd_pin == None or vdd_pin.lx()<left_bank_vdd_pin.lx():
left_bank_vdd_pin = vdd_pin
if right_bank_vdd_pin == None or vdd_pin.lx()>right_bank_vdd_pin.lx():
right_bank_vdd_pin = vdd_pin
# Route to top
self.add_rect(layer="metal2",
offset=vdd_pin.ul(),
height=self.height-vdd_pin.uy(),
width=vdd_pin.width())
gnd_pins = self.bank_inst[1].get_pins("gnd")
highest_x = None
for bank_gnd_pin in gnd_pins:
if highest_x == None or bank_gnd_pin.lx()>highest_x:
highest_x = bank_gnd_pin.lx()
bank_gnd_pos = bank_gnd_pin.ul()
# Route to top
self.add_rect(layer="metal2",
offset=bank_gnd_pos,
height=self.height-bank_gnd_pos.y,
width=bank_gnd_pin.width())
left_bank_gnd_pin = None
right_bank_gnd_pin = None
for gnd_pin in gnd_pins:
if gnd_pin.layer != "metal2":
continue
if left_bank_gnd_pin == None or gnd_pin.lx()<left_bank_gnd_pin.lx():
left_bank_gnd_pin = gnd_pin
if right_bank_gnd_pin == None or gnd_pin.lx()>right_bank_gnd_pin.lx():
right_bank_gnd_pin = gnd_pin
# Route to top
self.add_rect(layer="metal2",
offset=gnd_pin.ul(),
height=self.height-gnd_pin.uy(),
width=gnd_pin.width())
# Connect bank decoder vdd/gnd supplies using the previous bank_vdd_pos and bank_gnd_pos
# Connect bank decoder vdd/gnd supplies using the previous bank pins
vdd_pins = self.msb_decoder_inst.get_pins("vdd")
for vdd_pin in vdd_pins:
if vdd_pin.layer != "metal1": continue
vdd_pos = vdd_pin.rc()
rail_pos = vector(bank_vdd_pos.x+bank_vdd_pin.width(),vdd_pos.y)
self.add_path("metal1",[vdd_pos,rail_pos])
if vdd_pin.layer != "metal1":
continue
rail1_pos = vector(left_bank_vdd_pin.cx(),vdd_pin.cy())
rail2_pos = vector(right_bank_vdd_pin.cx(),vdd_pin.cy())
self.add_path("metal1",[rail1_pos,rail2_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail1_pos,
rotate=90,
size=[1,3])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail2_pos,
rotate=90,
size=[1,3])
gnd_pins = self.msb_decoder_inst.get_pins("gnd")
for gnd_pin in gnd_pins:
if gnd_pin.layer != "metal1": continue
gnd_pos = gnd_pin.rc()
rail_pos = vector(bank_gnd_pos.x+bank_gnd_pin.width(),gnd_pos.y)
self.add_path("metal1",[gnd_pos,rail_pos])
self.add_via(("metal1","via1","metal2"),rail_pos- vector(0,0.5*self.m1_width),rotate=90,size=[1,3])
if gnd_pin.layer != "metal1":
continue
rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy())
rail2_pos = vector(right_bank_gnd_pin.cx(),gnd_pin.cy())
self.add_path("metal1",[rail1_pos,rail2_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail1_pos,
rotate=90,
size=[1,3])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail2_pos,
rotate=90,
size=[1,3])
# connect the bank MSB flop supplies
vdd_pins = self.msb_address_inst.get_pins("vdd")
# vdd pins go down to the rail
for vdd_pin in vdd_pins:
if vdd_pin.layer != "metal1": continue
if vdd_pin.layer != "metal1":
continue
vdd_pos = vdd_pin.bc()
down_pos = vdd_pos - vector(0,self.m1_pitch)
rail_pos = vector(vdd_pos.x,self.horz_control_bus_positions["vdd"].y)
self.add_path("metal1",[vdd_pos,down_pos])
self.add_via_center(("metal1","via1","metal2"),down_pos,rotate=90)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=down_pos,
rotate=90)
self.add_path("metal2",[down_pos,rail_pos])
self.add_via_center(("metal1","via1","metal2"),rail_pos)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail_pos)
# gnd pins go right to the rail
gnd_pins = self.msb_address_inst.get_pins("gnd")
for gnd_pin in gnd_pins:
if gnd_pin.layer != "metal2": continue
gnd_pos = gnd_pin.rc()
rail_pos = vector(bank_gnd_pos.x+bank_gnd_pin.width(),gnd_pos.y)
self.add_path("metal1",[gnd_pos,rail_pos])
self.add_via_center(("metal1","via1","metal2"),gnd_pos,rotate=90)
self.add_via(("metal1","via1","metal2"),rail_pos- vector(0,0.5*self.m1_width),rotate=90,size=[1,3])
if gnd_pin.layer != "metal2":
continue
rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy())
self.add_path("metal1",[rail1_pos,gnd_pin.lc()])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=gnd_pin.lc(),
rotate=90)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail1_pos,
rotate=90,
size=[1,3])
def route_single_msb_address(self):
""" Route one MSB address bit for 2-bank SRAM """
@ -681,65 +717,65 @@ class sram(design.design):
def route_bank_supply_rails(self, bottom_banks):
def route_bank_supply_rails(self, left_banks, bottom_banks):
""" Create rails at bottom. Connect veritcal rails to top and bottom. """
self.add_layout_pin(text="gnd",
layer="metal1",
offset=vector(0,0),
height=self.power_rail_width,
width=self.width)
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vector(0,self.power_rail_pitch),
height=self.power_rail_width,
width=self.width)
for i in left_banks:
vdd_pins = self.bank_inst[i].get_pins("vdd")
for vdd_pin in vdd_pins:
if vdd_pin.layer != "metal1":
continue
self.add_layout_pin(text="vdd",
layer=vdd_pin.layer,
offset=vdd_pin.ll(),
height=vdd_pin.height(),
width=self.width)
gnd_pins = self.bank_inst[i].get_pins("gnd")
for gnd_pin in gnd_pins:
if gnd_pin.layer != "metal1":
continue
self.add_layout_pin(text="gnd",
layer=gnd_pin.layer,
offset=gnd_pin.ll(),
height=gnd_pin.height(),
width=self.width)
# route bank vertical rails to bottom
for i in bottom_banks:
vdd_pins = self.bank_inst[i].get_pins("vdd")
for vdd_pin in vdd_pins:
vdd_pos = vdd_pin.ul()
# Route to bottom
self.add_rect(layer="metal2",
offset=vector(vdd_pos.x,self.power_rail_pitch),
height=self.horz_control_bus_positions["vdd"].y-self.power_rail_pitch,
if vdd_pin.layer != "metal2":
continue
# Route from bottom to top
self.add_rect(layer=vdd_pin.layer,
offset=vdd_pin.ll(),
height=self.horz_control_bus_positions["vdd"].y,
width=vdd_pin.width())
# Add vias at top
rail_pos = vector(vdd_pin.ur().x,self.horz_control_bus_positions["vdd"].y)
self.add_via(layers=("metal1","via1","metal2"),
offset=rail_pos - vector(0,0.5*self.m1_width),
rotate=90,
size=[1,3])
# Add vias at bottom
rail_pos = vector(vdd_pin.lr().x,self.power_rail_pitch)
self.add_via(layers=("metal1","via1","metal2"),
rail_pos = vector(vdd_pin.cx(),self.horz_control_bus_positions["vdd"].y)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail_pos,
rotate=90,
size=[2,3])
size=[1,3])
gnd_pins = self.bank_inst[i].get_pins("gnd")
for gnd_pin in gnd_pins:
gnd_pos = gnd_pin.ul()
# Route to bottom
self.add_rect(layer="metal2",
offset=vector(gnd_pos.x,0),
height=self.horz_control_bus_positions["gnd"].y, # route to the top bank
if gnd_pin.layer != "metal2":
continue
# Route from bottom to top
self.add_rect(layer=gnd_pin.layer,
offset=gnd_pin.ll(),
height=self.horz_control_bus_positions["gnd"].y,
width=gnd_pin.width())
# Add vias at top
right_rail_pos = vector(gnd_pin.ur().x,self.horz_control_bus_positions["gnd"].y)
self.add_via(layers=("metal1","via1","metal2"),
offset=right_rail_pos - vector(0,0.5*self.m1_width),
rail_pos = vector(gnd_pin.cx(),self.horz_control_bus_positions["gnd"].y)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=rail_pos,
rotate=90,
size=[1,3])
# Add vias at bottom
right_rail_pos = vector(gnd_pin.lr().x,0)
self.add_via(layers=("metal2","via2","metal3"),
offset=right_rail_pos,
rotate=90,
size=[2,3])
size=[1,3])
@ -775,9 +811,9 @@ class sram(design.design):
self.bank_count = 0
self.power_rail_width = self.bank.vdd_rail_width
self.supply_rail_width = self.bank.supply_rail_width
# Leave some extra space for the pitch
self.power_rail_pitch = self.bank.vdd_rail_width + 2*self.m3_space
self.supply_rail_pitch = self.bank.supply_rail_pitch
@ -897,12 +933,13 @@ class sram(design.design):
# No orientation or offset
self.bank_inst = self.add_bank(0, [0, 0], 1, 1)
# Control logic is placed to the left of the blank even with the
# decoder bottom. A small gap is in the x-dimension.
# 3/5/18 MRG: Cannot reference positions inside submodules because boundaries
# are not recomputed using instance placement. So, place the control logic such that it aligns
# with the top of the SRAM.
control_gap = 2*self.m3_width
pos = vector(-control_gap,
self.bank.row_decoder_inst.by() + 2*self.m3_width)
self.bank.height-self.control_logic.width)
self.add_control_logic(position=pos,
rotate=90)
@ -930,7 +967,7 @@ class sram(design.design):
def add_two_banks(self):
# Placement of bank 0 (left)
bank_position_0 = vector(self.bank.width,
self.bank.height + 2*self.power_rail_pitch)
self.bank.height)
self.bank_inst=[self.add_bank(0, bank_position_0, -1, -1)]
# Placement of bank 1 (right)
@ -943,7 +980,7 @@ class sram(design.design):
# Placement of bank 0 (upper left)
bank_position_0 = vector(self.bank.width,
self.bank.height + self.data_bus_height + 2*self.bank_to_bus_distance + 2*self.power_rail_pitch)
self.bank.height + self.data_bus_height + 2*self.bank_to_bus_distance)
self.bank_inst=[self.add_bank(0, bank_position_0, 1, -1)]
# Placement of bank 1 (upper right)
@ -952,7 +989,7 @@ class sram(design.design):
self.bank_inst.append(self.add_bank(1, bank_position_1, 1, 1))
# Placement of bank 2 (bottom left)
y_off = self.bank.height + 2*self.power_rail_pitch
y_off = self.bank.height
bank_position_2 = vector(bank_position_0.x, y_off)
self.bank_inst.append(self.add_bank(2, bank_position_2, -1, -1))
@ -983,19 +1020,33 @@ class sram(design.design):
dest_pin = self.bank_inst.get_pin(n)
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
# Find the left-most metal2 rails
leftmost_vdd_rail = None
for vdd_pin in self.bank_inst.get_pins("vdd"):
if vdd_pin.layer != "metal2":
continue
if leftmost_vdd_rail == None or vdd_pin.lx() < leftmost_vdd_rail.lx():
leftmost_vdd_rail = vdd_pin
leftmost_gnd_rail = None
for gnd_pin in self.bank_inst.get_pins("gnd"):
if gnd_pin.layer != "metal2":
continue
if leftmost_gnd_rail == None or gnd_pin.lx() < leftmost_gnd_rail.lx():
leftmost_gnd_rail = gnd_pin
src_pins = self.control_logic_inst.get_pins("vdd")
for src_pin in src_pins:
if src_pin.layer != "metal2":
continue
dest_pin = self.bank_inst.get_pins("vdd")[1]
self.connect_rail_from_left_m2m1(src_pin,dest_pin)
self.connect_rail_from_left_m2m3(src_pin,leftmost_vdd_rail)
src_pins = self.control_logic_inst.get_pins("gnd")
for src_pin in src_pins:
if src_pin.layer != "metal2":
continue
dest_pin = self.bank_inst.get_pin("gnd")
self.connect_rail_from_left_m2m3(src_pin,dest_pin)
self.add_path("metal2", [src_pin.rc(), vector(leftmost_gnd_rail.cx(), src_pin.cy())])