mirror of https://github.com/VLSIDA/OpenRAM.git
SRAM single bank passing DRC/LVS.
This commit is contained in:
parent
3ea003c367
commit
d29dd03373
564
compiler/bank.py
564
compiler/bank.py
|
|
@ -38,13 +38,24 @@ class bank(design.design):
|
||||||
self.words_per_row = words_per_row
|
self.words_per_row = words_per_row
|
||||||
self.num_banks = num_banks
|
self.num_banks = num_banks
|
||||||
|
|
||||||
|
# The local control signals are gated when we have bank select logic,
|
||||||
|
# so this prefix will be added to all of the signals.
|
||||||
|
if self.num_banks>1:
|
||||||
|
self.prefix="gated_"
|
||||||
|
else:
|
||||||
|
self.prefix=""
|
||||||
|
|
||||||
self.compute_sizes()
|
self.compute_sizes()
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.create_modules()
|
self.create_modules()
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
self.setup_layout_constraints()
|
self.setup_layout_constraints()
|
||||||
self.route_layout()
|
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!
|
# Can remove the following, but it helps for debug!
|
||||||
self.add_lvs_correspondence_points()
|
self.add_lvs_correspondence_points()
|
||||||
|
|
||||||
|
|
@ -61,14 +72,9 @@ class bank(design.design):
|
||||||
# the signals gated_*.
|
# the signals gated_*.
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
self.add_pin("bank_select")
|
self.add_pin("bank_select")
|
||||||
self.add_pin("s_en")
|
for pin in ["s_en","w_en","tri_en_bar","tri_en",
|
||||||
self.add_pin("w_en")
|
"clk_bar","clk","vdd","gnd"]:
|
||||||
self.add_pin("tri_en_bar")
|
self.add_pin(pin)
|
||||||
self.add_pin("tri_en")
|
|
||||||
self.add_pin("clk_bar")
|
|
||||||
self.add_pin("clk")
|
|
||||||
self.add_pin("vdd")
|
|
||||||
self.add_pin("gnd")
|
|
||||||
|
|
||||||
def route_layout(self):
|
def route_layout(self):
|
||||||
""" Create routing amoung the modules """
|
""" Create routing amoung the modules """
|
||||||
|
|
@ -82,12 +88,11 @@ class bank(design.design):
|
||||||
self.route_msf_address()
|
self.route_msf_address()
|
||||||
self.route_control_lines()
|
self.route_control_lines()
|
||||||
self.add_control_pins()
|
self.add_control_pins()
|
||||||
if self.num_banks > 1:
|
|
||||||
self.route_bank_select()
|
|
||||||
self.route_vdd_supply()
|
self.route_vdd_supply()
|
||||||
self.route_gnd_supply()
|
self.route_gnd_supply()
|
||||||
|
|
||||||
#self.offset_all_coordinates()
|
self.offset_all_coordinates()
|
||||||
|
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
""" Add modules. The order should not matter! """
|
""" Add modules. The order should not matter! """
|
||||||
|
|
@ -109,8 +114,6 @@ class bank(design.design):
|
||||||
self.add_row_decoder()
|
self.add_row_decoder()
|
||||||
self.add_wordline_driver()
|
self.add_wordline_driver()
|
||||||
self.add_msf_address()
|
self.add_msf_address()
|
||||||
if(self.num_banks > 1):
|
|
||||||
self.add_bank_select()
|
|
||||||
|
|
||||||
def compute_sizes(self):
|
def compute_sizes(self):
|
||||||
""" Computes the required sizes to create the bank """
|
""" Computes the required sizes to create the bank """
|
||||||
|
|
@ -132,9 +135,12 @@ class bank(design.design):
|
||||||
# Number of control lines in the bus
|
# Number of control lines in the bus
|
||||||
self.num_control_lines = 6
|
self.num_control_lines = 6
|
||||||
# The order of the control signals on the control bus:
|
# The order of the control signals on the control bus:
|
||||||
self.control_signals = ["clk", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"]
|
self.input_control_signals = ["clk", "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.control_signals]
|
self.control_signals = ["gated_"+str for str in self.input_control_signals]
|
||||||
|
else:
|
||||||
|
self.control_signals = self.input_control_signals
|
||||||
# The central bus is the column address (both polarities), row address
|
# The central bus is the column address (both polarities), row address
|
||||||
if self.col_addr_size>0:
|
if self.col_addr_size>0:
|
||||||
self.num_addr_lines = 2**self.col_addr_size + self.row_addr_size
|
self.num_addr_lines = 2**self.col_addr_size + self.row_addr_size
|
||||||
|
|
@ -146,6 +152,7 @@ class bank(design.design):
|
||||||
self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3"))
|
self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3"))
|
||||||
self.m1_pitch = self.m1m2_via.height + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"])
|
self.m1_pitch = self.m1m2_via.height + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"])
|
||||||
self.m2_pitch = self.m2m3_via.height + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"])
|
self.m2_pitch = self.m2m3_via.height + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"])
|
||||||
|
self.m1_width = drc["minwidth_metal1"]
|
||||||
self.m2_width = drc["minwidth_metal2"]
|
self.m2_width = drc["minwidth_metal2"]
|
||||||
self.m3_width = drc["minwidth_metal3"]
|
self.m3_width = drc["minwidth_metal3"]
|
||||||
|
|
||||||
|
|
@ -212,13 +219,6 @@ class bank(design.design):
|
||||||
self.inv = pinv()
|
self.inv = pinv()
|
||||||
self.add_mod(self.inv)
|
self.add_mod(self.inv)
|
||||||
|
|
||||||
# 4x Inverter
|
|
||||||
self.inv4x = pinv(nmos_width=4*drc["minwidth_tx"])
|
|
||||||
self.add_mod(self.inv4x)
|
|
||||||
|
|
||||||
self.nor2 = nor_2()
|
|
||||||
self.add_mod(self.nor2)
|
|
||||||
|
|
||||||
# Vertical metal rail gap definition
|
# Vertical metal rail gap definition
|
||||||
self.metal2_extend_contact = (self.m1m2_via.second_layer_height
|
self.metal2_extend_contact = (self.m1m2_via.second_layer_height
|
||||||
- self.m1m2_via.contact_width) / 2
|
- self.m1m2_via.contact_width) / 2
|
||||||
|
|
@ -226,6 +226,7 @@ class bank(design.design):
|
||||||
self.gap_between_rail_offset = self.gap_between_rails + drc["minwidth_metal2"]
|
self.gap_between_rail_offset = self.gap_between_rails + drc["minwidth_metal2"]
|
||||||
self.via_shift = (self.m1m2_via.second_layer_width
|
self.via_shift = (self.m1m2_via.second_layer_width
|
||||||
- self.m1m2_via.first_layer_width) / 2
|
- self.m1m2_via.first_layer_width) / 2
|
||||||
|
self.via_shift_offset = vector(0,self.via_shift)
|
||||||
|
|
||||||
def add_bitcell_array(self):
|
def add_bitcell_array(self):
|
||||||
""" Adding Bitcell Array """
|
""" Adding Bitcell Array """
|
||||||
|
|
@ -257,7 +258,7 @@ class bank(design.design):
|
||||||
for i in range(self.num_cols):
|
for i in range(self.num_cols):
|
||||||
temp.append("bl[{0}]".format(i))
|
temp.append("bl[{0}]".format(i))
|
||||||
temp.append("br[{0}]".format(i))
|
temp.append("br[{0}]".format(i))
|
||||||
temp.extend(["clk_bar", "vdd"])
|
temp.extend([self.prefix+"clk_bar", "vdd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_column_mux_array(self):
|
def add_column_mux_array(self):
|
||||||
|
|
@ -296,7 +297,7 @@ class bank(design.design):
|
||||||
temp.append("bl_out[{0}]".format(i))
|
temp.append("bl_out[{0}]".format(i))
|
||||||
temp.append("br_out[{0}]".format(i))
|
temp.append("br_out[{0}]".format(i))
|
||||||
|
|
||||||
temp.extend(["s_en", "vdd", "gnd"])
|
temp.extend([self.prefix+"s_en", "vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_write_driver_array(self):
|
def add_write_driver_array(self):
|
||||||
|
|
@ -317,7 +318,7 @@ class bank(design.design):
|
||||||
else:
|
else:
|
||||||
temp.append("bl_out[{0}]".format(i))
|
temp.append("bl_out[{0}]".format(i))
|
||||||
temp.append("br_out[{0}]".format(i))
|
temp.append("br_out[{0}]".format(i))
|
||||||
temp.extend(["w_en", "vdd", "gnd"])
|
temp.extend([self.prefix+"w_en", "vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_msf_data_in(self):
|
def add_msf_data_in(self):
|
||||||
|
|
@ -335,7 +336,7 @@ class bank(design.design):
|
||||||
for i in range(self.word_size):
|
for i in range(self.word_size):
|
||||||
temp.append("data_in[{0}]".format(i))
|
temp.append("data_in[{0}]".format(i))
|
||||||
temp.append("data_in_bar[{0}]".format(i))
|
temp.append("data_in_bar[{0}]".format(i))
|
||||||
temp.extend(["clk_bar", "vdd", "gnd"])
|
temp.extend([self.prefix+"clk_bar", "vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_tri_gate_array(self):
|
def add_tri_gate_array(self):
|
||||||
|
|
@ -351,7 +352,7 @@ class bank(design.design):
|
||||||
temp.append("data_out[{0}]".format(i))
|
temp.append("data_out[{0}]".format(i))
|
||||||
for i in range(self.word_size):
|
for i in range(self.word_size):
|
||||||
temp.append("DATA[{0}]".format(i))
|
temp.append("DATA[{0}]".format(i))
|
||||||
temp.extend(["tri_en", "tri_en_bar", "vdd", "gnd"])
|
temp.extend([self.prefix+"tri_en", self.prefix+"tri_en_bar", "vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_row_decoder(self):
|
def add_row_decoder(self):
|
||||||
|
|
@ -396,11 +397,7 @@ class bank(design.design):
|
||||||
temp.append("dec_out[{0}]".format(i))
|
temp.append("dec_out[{0}]".format(i))
|
||||||
for i in range(self.num_rows):
|
for i in range(self.num_rows):
|
||||||
temp.append("wl[{0}]".format(i))
|
temp.append("wl[{0}]".format(i))
|
||||||
|
temp.append(self.prefix+"clk")
|
||||||
if(self.num_banks > 1):
|
|
||||||
temp.append("gated_clk")
|
|
||||||
else:
|
|
||||||
temp.append("clk")
|
|
||||||
temp.append("vdd")
|
temp.append("vdd")
|
||||||
temp.append("gnd")
|
temp.append("gnd")
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
@ -429,10 +426,7 @@ class bank(design.design):
|
||||||
temp.extend(["sel[1]","sel[0]"])
|
temp.extend(["sel[1]","sel[0]"])
|
||||||
else:
|
else:
|
||||||
temp.extend(["A[{0}]".format(i),"A_bar[{0}]".format(i)])
|
temp.extend(["A[{0}]".format(i),"A_bar[{0}]".format(i)])
|
||||||
if(self.num_banks > 1):
|
temp.append(self.prefix+"clk")
|
||||||
temp.append("gated_clk")
|
|
||||||
else:
|
|
||||||
temp.append("clk")
|
|
||||||
temp.extend(["vdd", "gnd"])
|
temp.extend(["vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
|
@ -440,12 +434,15 @@ class bank(design.design):
|
||||||
def add_column_decoder(self):
|
def add_column_decoder(self):
|
||||||
""" Create a 2:4 decoder to decode column select lines if the col_addr_size = 4 """
|
""" Create a 2:4 decoder to decode column select lines if the col_addr_size = 4 """
|
||||||
|
|
||||||
# FIXME: Should just load this rather than reference a level down
|
|
||||||
if self.col_addr_size == 1:
|
if self.col_addr_size == 1:
|
||||||
return # This is done from the FF outputs directly
|
return # This is done from the FF outputs directly
|
||||||
if self.col_addr_size == 2:
|
if self.col_addr_size == 2:
|
||||||
|
# FIXME: Should just load this rather than reference a level down
|
||||||
self.col_decoder = self.decoder.pre2_4
|
self.col_decoder = self.decoder.pre2_4
|
||||||
elif self.col_addr_size == 3:
|
elif self.col_addr_size == 3:
|
||||||
|
debug.error("8 way column mux not yet supported...", -1)
|
||||||
|
# FIXME: Should just load this rather than reference a level down
|
||||||
self.col_decoder = self.decoder.pre3_8
|
self.col_decoder = self.decoder.pre3_8
|
||||||
else:
|
else:
|
||||||
# No error checking before?
|
# No error checking before?
|
||||||
|
|
@ -473,103 +470,182 @@ class bank(design.design):
|
||||||
NOR+INV gates to gate the control signals in case of multiple
|
NOR+INV gates to gate the control signals in case of multiple
|
||||||
banks are created in upper level SRAM module
|
banks are created in upper level SRAM module
|
||||||
"""
|
"""
|
||||||
xoffset_nor = self.start_of_left_central_bus + self.nor2.width + self.inv4x.width
|
|
||||||
xoffset_inv = xoffset_nor + self.nor2.width
|
# 4x Inverter
|
||||||
self.bank_select_or_position = vector(-xoffset_nor, self.min_point)
|
self.inv4x = pinv(nmos_width=4*drc["minwidth_tx"])
|
||||||
|
self.add_mod(self.inv4x)
|
||||||
|
|
||||||
|
self.nor2 = nor_2()
|
||||||
|
self.add_mod(self.nor2)
|
||||||
|
|
||||||
|
self.nand2 = nand_2()
|
||||||
|
self.add_mod(self.nand2)
|
||||||
|
|
||||||
|
# left of gnd rail is the "bus start"
|
||||||
|
bus_start = self.gnd_x_offset - 2*drc["minwidth_metal2"]
|
||||||
|
xoffset_nand = bus_start - self.nand2.width - self.inv4x.width - 2*self.m2_pitch
|
||||||
|
xoffset_nor = bus_start - self.nor2.width - self.inv4x.width - 2*self.m2_pitch
|
||||||
|
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
|
# bank select inverter
|
||||||
self.bank_select_inv_position = vector(self.bank_select_or_position.x
|
self.bank_select_inv_position = vector(xoffset_bank_sel_inv,
|
||||||
- 5 * drc["minwidth_metal2"]
|
|
||||||
- self.inv4x.width,
|
|
||||||
self.min_point)
|
self.min_point)
|
||||||
self.add_inst(name="bank_select_inv",
|
# bank select inverter (must be made unique if more than one OR)
|
||||||
mod=self.inv4x,
|
bank_sel_inv=self.add_inst(name="bank_sel_inv",
|
||||||
offset=self.bank_select_inv_position)
|
mod=self.inv,
|
||||||
self.connect_inst(["bank_select", "bank_select_bar", "vdd", "gnd"])
|
offset=[xoffset_bank_sel_inv,self.min_point])
|
||||||
|
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
|
||||||
|
|
||||||
for i in range(self.numb_control_lines):
|
# bank_sel is vertical wire
|
||||||
# central control bus index
|
xoffset_bank_sel = xoffset_bank_sel_inv
|
||||||
# 5 = clk,4 = tri_en_bar,3 = tri_en,2 = clk_bar,1 = w_en,0 = s_en
|
self.add_label_pin(text="bank_sel",
|
||||||
name_nor = "bank_selector_nor_{0}".format(i)
|
layer="metal2",
|
||||||
name_inv = "bank_selector_inv_{0}".format(i)
|
offset=vector(xoffset_bank_sel, self.min_point),
|
||||||
nor2_inv_connection_height = self.inv4x.A_position.y - self.nor2.Z_position.y + 0.5 * drc["minwidth_metal1"]
|
width=self.m2_width,
|
||||||
|
height=self.decoder_min_point-self.min_point-self.m2_pitch)
|
||||||
|
in_pin = bank_sel_inv.get_pin("A").ll()
|
||||||
|
self.add_via(layers=("metal1","via1","metal2"),
|
||||||
|
offset=in_pin)
|
||||||
|
self.add_layout_pin(text="bank_sel",
|
||||||
|
layer="metal3",
|
||||||
|
offset=vector(self.left_vdd_x_offset, self.min_point),
|
||||||
|
width=xoffset_bank_sel - self.left_vdd_x_offset,
|
||||||
|
height=self.m3_width)
|
||||||
|
self.add_via(layers=("metal2","via2","metal3"),
|
||||||
|
offset=vector(xoffset_bank_sel_inv, self.min_point))
|
||||||
|
|
||||||
if (i % 2):
|
# bank_sel_bar is vertical wire
|
||||||
y_offset = self.min_point + self.inv.height*(i + 1)
|
xoffset_bank_sel_bar = xoffset_bank_sel_inv+self.inv.width-self.m2_width
|
||||||
mod_dir = "MX"
|
self.add_label_pin(text="bank_sel_bar",
|
||||||
# nor2 output to inv input
|
layer="metal2",
|
||||||
y_correct = self.nor2.Z_position.y + nor2_inv_connection_height - 0.5 * drc["minwidth_metal1"]
|
offset=vector(xoffset_bank_sel_bar, self.min_point),
|
||||||
|
width=self.m2_width,
|
||||||
|
height=2*self.inv.height)
|
||||||
|
out_pin = bank_sel_inv.get_pin("Z").lr()
|
||||||
|
self.add_via(layers=("metal1","via1","metal2"),
|
||||||
|
offset=out_pin-vector(self.m2_width,0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
y_offset = self.min_point + self.inv.height * i
|
||||||
|
if i%2:
|
||||||
|
y_offset += self.inv.height
|
||||||
|
mirror = "MX"
|
||||||
else:
|
else:
|
||||||
y_offset = self.min_point + self.inv.height*i
|
mirror = ""
|
||||||
mod_dir = "R0"
|
|
||||||
# nor2 output to inv input
|
|
||||||
y_correct = 0.5 * drc["minwidth_metal1"] - self.nor2.Z_position.y
|
|
||||||
connection = vector(xoffset_inv, y_offset - y_correct)
|
|
||||||
|
|
||||||
if i == 3:
|
# These require OR (nor2+inv) gates since they are active low.
|
||||||
self.add_inst(name=name_nor,
|
# (writes occur on clk low)
|
||||||
mod=self.nor2,
|
if input_name in ("clk", "tri_en_bar"):
|
||||||
offset=[xoffset_nor, y_offset],
|
|
||||||
mirror=mod_dir)
|
logic_inst=self.add_inst(name=name_nor,
|
||||||
self.connect_inst(["gated_tri_en_bar",
|
mod=self.nor2,
|
||||||
"bank_select_bar",
|
offset=[xoffset_nor, y_offset],
|
||||||
self.control_signals[i].format(i),
|
mirror=mirror)
|
||||||
|
self.connect_inst([input_name,
|
||||||
|
"bank_sel_bar",
|
||||||
|
gated_name+"_temp_bar",
|
||||||
"vdd",
|
"vdd",
|
||||||
"gnd"])
|
"gnd"])
|
||||||
# connect the metal1 layer to connect to the old inv output
|
xoffset_bank_signal = xoffset_bank_sel_bar
|
||||||
offset = connection - vector(0, 0.5*drc["minwidth_metal1"])
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=offset,
|
# the rest are AND (nand2+inv) gates
|
||||||
width=self.inv4x.width,
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
elif i == 5:
|
|
||||||
offset = [xoffset_nor, y_offset - self.nor2.A_position.y
|
|
||||||
- 0.5*drc["minwidth_metal1"]]
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=offset,
|
|
||||||
width=self.nor2.width + self.inv4x.width,
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
else:
|
else:
|
||||||
self.add_inst(name=name_nor,
|
logic_inst=self.add_inst(name=name_nand,
|
||||||
mod=self.nor2,
|
mod=self.nand2,
|
||||||
offset=[xoffset_nor, y_offset],
|
offset=[xoffset_nand, y_offset],
|
||||||
mirror=mod_dir)
|
mirror=mirror)
|
||||||
self.connect_inst([self.gated_control_signals[i],
|
bank_sel_signal = "bank_sel"
|
||||||
"bank_select_bar",
|
self.connect_inst([input_name,
|
||||||
"net_block_nor_inv[{0}]".format(i),
|
"bank_sel",
|
||||||
|
gated_name+"_temp_bar",
|
||||||
"vdd",
|
"vdd",
|
||||||
"gnd"])
|
"gnd"])
|
||||||
|
xoffset_bank_signal = xoffset_bank_sel
|
||||||
|
|
||||||
self.add_inst(name=name_inv,
|
# They all get inverters on the output
|
||||||
mod=self.inv4x,
|
inv_inst=self.add_inst(name=name_inv,
|
||||||
offset=[xoffset_inv, y_offset],
|
mod=self.inv4x,
|
||||||
mirror=mod_dir)
|
offset=[xoffset_inv, y_offset],
|
||||||
self.connect_inst(["net_block_nor_inv[{0}]".format(i),
|
mirror=mirror)
|
||||||
self.control_signals[i],
|
self.connect_inst([gated_name+"_temp_bar",
|
||||||
"vdd",
|
gated_name,
|
||||||
"gnd"])
|
"vdd",
|
||||||
|
"gnd"])
|
||||||
|
|
||||||
# nor2 output to inv input
|
|
||||||
for i in range(self.numb_control_lines - 1):
|
|
||||||
nor2_inv_connection_height = (self.inv4x.A_position.y
|
|
||||||
- self.nor2.Z_position.y
|
|
||||||
+ 0.5 * drc["minwidth_metal1"])
|
|
||||||
|
|
||||||
if (i % 2):
|
# Connect the logic output to inverter input
|
||||||
y_offset = self.min_point + self.inv.height * (i + 1)
|
pre = logic_inst.get_pin("Z").lc()
|
||||||
mod_dir = "MX"
|
out_position = logic_inst.get_pin("Z").rc() + vector(0.5*self.m1_width,0)
|
||||||
y_correct = (-self.nor2.Z_position.y + 0.5 * drc["minwidth_metal1"]
|
in_position = inv_inst.get_pin("A").lc() + vector(0.5*self.m1_width,0)
|
||||||
- nor2_inv_connection_height)
|
post = inv_inst.get_pin("A").rc()
|
||||||
else:
|
self.add_path("metal1", [pre, out_position, in_position, post])
|
||||||
y_offset = self.min_point + self.inv.height*i
|
|
||||||
mod_dir = "R0"
|
# Connect the inverter output to the central bus
|
||||||
y_correct = self.nor2.Z_position.y - 0.5 * drc["minwidth_metal1"]
|
out_pin = inv_inst.get_pin("Z")
|
||||||
# nor2 output to inv input
|
bus_pos = vector(self.central_line_xoffset[gated_name], out_pin.rc().y)
|
||||||
connection = vector(xoffset_inv, y_offset + y_correct)
|
self.add_path("metal3",[out_pin.rc(), bus_pos])
|
||||||
self.add_rect(layer="metal1",
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
offset=connection,
|
offset=bus_pos - vector(0,0.5*self.m2m3_via.height))
|
||||||
width=drc["minwidth_metal1"],
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
height=nor2_inv_connection_height)
|
offset=out_pin.lr() - self.via_shift_offset,
|
||||||
|
rotate=90)
|
||||||
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
|
offset=out_pin.lr() - self.via_shift_offset,
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
# Connect the logic B input to bank_sel/bank_sel_bar
|
||||||
|
logic_pin = logic_inst.get_pin("B")
|
||||||
|
input_pos = vector(xoffset_bank_signal,logic_pin.cy())
|
||||||
|
self.add_path("metal2",[logic_pin.lc(), input_pos])
|
||||||
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
|
offset=logic_pin.ll()-self.via_shift_offset,
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
|
||||||
|
# Connect the logic A input to the input pin
|
||||||
|
logic_pos = logic_inst.get_pin("A").ll()
|
||||||
|
input_pos = vector(self.left_vdd_x_offset,logic_pos.y)
|
||||||
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
|
offset=logic_pos-self.via_shift_offset,
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
|
offset=logic_pos-self.via_shift_offset,
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
self.add_layout_pin(text=input_name,
|
||||||
|
layer="metal3",
|
||||||
|
offset=vector(self.left_vdd_x_offset,logic_pos.y - self.via_shift_offset.y),
|
||||||
|
height=self.m3_width,
|
||||||
|
width=logic_pos.x-self.left_vdd_x_offset)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Add vdd/gnd supply rails
|
||||||
|
gnd_pin = inv_inst.get_pin("gnd")
|
||||||
|
left_gnd_pos = vector(xoffset_bank_sel_inv,gnd_pin.rc().y)
|
||||||
|
right_gnd_pos = vector(self.gnd_x_offset,gnd_pin.rc().y)
|
||||||
|
self.add_path("metal1",[left_gnd_pos, right_gnd_pos])
|
||||||
|
right_via_pos = vector(self.gnd_x_offset,gnd_pin.lr().y)
|
||||||
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
|
offset=right_via_pos + vector(self.m1m2_via.height,0) - self.via_shift_offset,
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
vdd_pin = inv_inst.get_pin("vdd")
|
||||||
|
left_vdd_pos = vector(self.left_vdd_x_offset,vdd_pin.lc().y)
|
||||||
|
self.add_path("metal1",[left_vdd_pos,vdd_pin.rc()])
|
||||||
|
|
||||||
|
|
||||||
def setup_layout_constraints(self):
|
def setup_layout_constraints(self):
|
||||||
""" Calculating layout constraints, width, height etc """
|
""" Calculating layout constraints, width, height etc """
|
||||||
|
|
@ -580,13 +656,17 @@ class bank(design.design):
|
||||||
# Leave room for the output below the tri gate.
|
# Leave room for the output below the tri gate.
|
||||||
tri_gate_min_point = self.tri_gate_array_inst.ll().y - 3*self.m2_pitch
|
tri_gate_min_point = self.tri_gate_array_inst.ll().y - 3*self.m2_pitch
|
||||||
addr_min_point = self.msf_address_inst.ll().y - 2*self.m2_pitch
|
addr_min_point = self.msf_address_inst.ll().y - 2*self.m2_pitch
|
||||||
|
|
||||||
if self.col_addr_size >1:
|
if self.col_addr_size >1:
|
||||||
decoder_min_point = self.col_decoder_inst.ll().y
|
self.decoder_min_point = self.col_decoder_inst.ll().y
|
||||||
else:
|
else:
|
||||||
decoder_min_point = 0
|
self.decoder_min_point = addr_min_point
|
||||||
self.min_point = min(tri_gate_min_point, addr_min_point, decoder_min_point)
|
|
||||||
if self.num_banks>1:
|
if self.num_banks>1:
|
||||||
self.min_point -= self.num_control_lines * self.bitcell.height
|
self.min_point = min(self.decoder_min_point - self.num_control_lines * self.bitcell.height, tri_gate_min_point)
|
||||||
|
else:
|
||||||
|
self.min_point = min(addr_min_point, tri_gate_min_point)
|
||||||
|
|
||||||
|
|
||||||
# The max point is always the top of the precharge bitlines
|
# The max point is always the top of the precharge bitlines
|
||||||
self.max_point = self.precharge_array_inst.uy()
|
self.max_point = self.precharge_array_inst.uy()
|
||||||
|
|
@ -594,7 +674,7 @@ class bank(design.design):
|
||||||
self.height = self.max_point - self.min_point
|
self.height = self.max_point - self.min_point
|
||||||
|
|
||||||
# Add an extra gap between the bitcell and the rail
|
# Add an extra gap between the bitcell and the rail
|
||||||
self.right_vdd_x_offset = self.bitcell_array_inst.ur().x + 3 * drc["minwidth_metal1"]
|
self.right_vdd_x_offset = self.bitcell_array_inst.ur().x + 3 * self.m1_width
|
||||||
offset = vector(self.right_vdd_x_offset, self.min_point)
|
offset = vector(self.right_vdd_x_offset, self.min_point)
|
||||||
self.add_layout_pin(text="vdd",
|
self.add_layout_pin(text="vdd",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
|
|
@ -603,7 +683,7 @@ class bank(design.design):
|
||||||
height=self.height)
|
height=self.height)
|
||||||
|
|
||||||
# from the edge of the decoder is another 2 times minwidth metal1
|
# from the edge of the decoder is another 2 times minwidth metal1
|
||||||
self.left_vdd_x_offset = min(self.msf_address_inst.ll().x, self.row_decoder_inst.ll().x) - self.vdd_rail_width - 2*drc["minwidth_metal1"]
|
self.left_vdd_x_offset = min(self.msf_address_inst.ll().x, self.row_decoder_inst.ll().x) - self.vdd_rail_width - 2*self.m1_width
|
||||||
offset = vector(self.left_vdd_x_offset, self.min_point)
|
offset = vector(self.left_vdd_x_offset, self.min_point)
|
||||||
self.add_layout_pin(text="vdd",
|
self.add_layout_pin(text="vdd",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
|
|
@ -640,7 +720,7 @@ class bank(design.design):
|
||||||
height=self.height)
|
height=self.height)
|
||||||
|
|
||||||
# row address lines (to the left of the column mux or GND rail)
|
# row address lines (to the left of the column mux or GND rail)
|
||||||
# goes from 0 down to the min point
|
# goes from 0 down to the bottom of the address flops
|
||||||
for i in range(self.row_addr_size):
|
for i in range(self.row_addr_size):
|
||||||
x_offset = self.start_of_left_central_bus + i * self.m2_pitch
|
x_offset = self.start_of_left_central_bus + i * self.m2_pitch
|
||||||
name = "A[{}]".format(i)
|
name = "A[{}]".format(i)
|
||||||
|
|
@ -648,9 +728,9 @@ class bank(design.design):
|
||||||
# Add a label pin for LVS correspondence and visual help inspecting the rail.
|
# Add a label pin for LVS correspondence and visual help inspecting the rail.
|
||||||
self.add_label_pin(text=name,
|
self.add_label_pin(text=name,
|
||||||
layer="metal2",
|
layer="metal2",
|
||||||
offset=vector(x_offset, self.min_point),
|
offset=vector(x_offset, self.decoder_min_point),
|
||||||
width=self.m2_width,
|
width=self.m2_width,
|
||||||
height=-self.min_point)
|
height=-self.decoder_min_point)
|
||||||
|
|
||||||
# column mux lines if there is column mux [2 or 4 lines] (to the left of the GND rail)
|
# column mux lines if there is column mux [2 or 4 lines] (to the left of the GND rail)
|
||||||
# goes from 0 down to the min point
|
# goes from 0 down to the min point
|
||||||
|
|
@ -662,9 +742,9 @@ class bank(design.design):
|
||||||
# Add a label pin for LVS correspondence
|
# Add a label pin for LVS correspondence
|
||||||
self.add_label_pin(text=name,
|
self.add_label_pin(text=name,
|
||||||
layer="metal2",
|
layer="metal2",
|
||||||
offset=vector(x_offset, self.min_point),
|
offset=vector(x_offset, self.decoder_min_point),
|
||||||
width=self.m2_width,
|
width=self.m2_width,
|
||||||
height=-self.min_point)
|
height=-self.decoder_min_point)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -691,7 +771,7 @@ class bank(design.design):
|
||||||
tri_gate_in = self.tri_gate_array_inst.get_pin("in[{}]".format(i)).bc()
|
tri_gate_in = self.tri_gate_array_inst.get_pin("in[{}]".format(i)).bc()
|
||||||
sa_data_out = self.sense_amp_array_inst.get_pin("data[{}]".format(i)).rc() # rc to get enough overlap
|
sa_data_out = self.sense_amp_array_inst.get_pin("data[{}]".format(i)).rc() # rc to get enough overlap
|
||||||
|
|
||||||
startY = self.tri_gate_array_inst.ll().y - 2*drc["minwidth_metal3"] + 0.5*drc["minwidth_metal1"]
|
startY = self.tri_gate_array_inst.ll().y - 2*drc["minwidth_metal3"] + 0.5*self.m1_width
|
||||||
start = vector(tri_gate_in.x - 3 * drc["minwidth_metal3"], startY)
|
start = vector(tri_gate_in.x - 3 * drc["minwidth_metal3"], startY)
|
||||||
|
|
||||||
m3_min = vector([drc["minwidth_metal3"]] * 2)
|
m3_min = vector([drc["minwidth_metal3"]] * 2)
|
||||||
|
|
@ -734,7 +814,7 @@ class bank(design.design):
|
||||||
|
|
||||||
# Connect the address rails to the decoder
|
# Connect the address rails to the decoder
|
||||||
# Note that the decoder inputs are long vertical rails so spread out the connections vertically.
|
# Note that the decoder inputs are long vertical rails so spread out the connections vertically.
|
||||||
decoder_in_position = self.row_decoder_inst.get_pin("A[{}]".format(i)).br() + vector(0,position_heights*self.bitcell.height+self.m2_pitch)
|
decoder_in_position = self.row_decoder_inst.get_pin("A[{}]".format(i)).lr() + vector(0,position_heights*self.bitcell.height+self.m2_pitch)
|
||||||
rail_position = vector(self.central_line_xoffset["A[{}]".format(i)]+drc["minwidth_metal2"],decoder_in_position.y)
|
rail_position = vector(self.central_line_xoffset["A[{}]".format(i)]+drc["minwidth_metal2"],decoder_in_position.y)
|
||||||
self.add_path("metal1",[decoder_in_position,rail_position])
|
self.add_path("metal1",[decoder_in_position,rail_position])
|
||||||
|
|
||||||
|
|
@ -778,8 +858,8 @@ class bank(design.design):
|
||||||
for i in range(self.num_rows):
|
for i in range(self.num_rows):
|
||||||
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
|
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
|
||||||
pre = self.row_decoder_inst.get_pin("decode[{}]".format(i)).lc()
|
pre = self.row_decoder_inst.get_pin("decode[{}]".format(i)).lc()
|
||||||
decoder_out_position = self.row_decoder_inst.get_pin("decode[{}]".format(i)).rc() + vector(0.5*drc["minwidth_metal1"],0)
|
decoder_out_position = self.row_decoder_inst.get_pin("decode[{}]".format(i)).rc() + vector(0.5*self.m1_width,0)
|
||||||
driver_in_position = self.wordline_driver_inst.get_pin("in[{}]".format(i)).lc() + vector(0.5*drc["minwidth_metal1"],0)
|
driver_in_position = self.wordline_driver_inst.get_pin("in[{}]".format(i)).lc() + vector(0.5*self.m1_width,0)
|
||||||
post = self.wordline_driver_inst.get_pin("in[{}]".format(i)).rc()
|
post = self.wordline_driver_inst.get_pin("in[{}]".format(i)).rc()
|
||||||
self.add_path("metal1", [pre, decoder_out_position, driver_in_position, post])
|
self.add_path("metal1", [pre, decoder_out_position, driver_in_position, post])
|
||||||
|
|
||||||
|
|
@ -839,7 +919,7 @@ class bank(design.design):
|
||||||
self.add_path("metal1",[decode_out_position, selx_position])
|
self.add_path("metal1",[decode_out_position, selx_position])
|
||||||
|
|
||||||
# via on end
|
# via on end
|
||||||
decode_out_via = self.col_decoder_inst.get_pin("out[{}]".format(i)).br()
|
decode_out_via = self.col_decoder_inst.get_pin("out[{}]".format(i)).lr()
|
||||||
selx_via = vector(self.central_line_xoffset[name],decode_out_via.y - drc["minwidth_metal2"])
|
selx_via = vector(self.central_line_xoffset[name],decode_out_via.y - drc["minwidth_metal2"])
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=selx_via)
|
offset=selx_via)
|
||||||
|
|
@ -870,7 +950,7 @@ class bank(design.design):
|
||||||
mid_position = vector(in_position.x,dout_position.y)
|
mid_position = vector(in_position.x,dout_position.y)
|
||||||
self.add_path("metal3",[dout_position, mid_position, in_position])
|
self.add_path("metal3",[dout_position, mid_position, in_position])
|
||||||
|
|
||||||
dout_via = self.msf_address_inst.get_pin("dout[{}]".format(ff_index)).br()
|
dout_via = self.msf_address_inst.get_pin("dout[{}]".format(ff_index)).lr()
|
||||||
in_via = self.col_decoder_inst.get_pin("in[{}]".format(i)).ul()
|
in_via = self.col_decoder_inst.get_pin("in[{}]".format(i)).ul()
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||||
offset=dout_via,
|
offset=dout_via,
|
||||||
|
|
@ -934,7 +1014,7 @@ class bank(design.design):
|
||||||
dout_position = self.msf_address_inst.get_pin("dout[{}]".format(i)).rc()
|
dout_position = self.msf_address_inst.get_pin("dout[{}]".format(i)).rc()
|
||||||
rail_position = vector(self.central_line_xoffset["A[{}]".format(i)]+drc["minwidth_metal2"],dout_position.y)
|
rail_position = vector(self.central_line_xoffset["A[{}]".format(i)]+drc["minwidth_metal2"],dout_position.y)
|
||||||
self.add_path("metal1",[dout_position, rail_position])
|
self.add_path("metal1",[dout_position, rail_position])
|
||||||
dout_via = self.msf_address_inst.get_pin("dout[{}]".format(i)).br() + vector(self.m1m2_via.height,0)
|
dout_via = self.msf_address_inst.get_pin("dout[{}]".format(i)).lr() + vector(self.m1m2_via.height,0)
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=dout_via,
|
offset=dout_via,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
@ -947,7 +1027,7 @@ class bank(design.design):
|
||||||
for gnd_pin in self.msf_address_inst.get_pins("gnd"):
|
for gnd_pin in self.msf_address_inst.get_pins("gnd"):
|
||||||
if gnd_pin.layer != "metal2":
|
if gnd_pin.layer != "metal2":
|
||||||
continue
|
continue
|
||||||
gnd_via = gnd_pin.br() + vector(self.m1m2_via.height,0)
|
gnd_via = gnd_pin.lr() + vector(self.m1m2_via.height,0)
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=gnd_via,
|
offset=gnd_via,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
@ -1019,16 +1099,12 @@ class bank(design.design):
|
||||||
# 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 = []
|
||||||
if self.num_banks>1:
|
connection.append((self.prefix+"clk_bar", self.msf_data_in_inst.get_pin("clk").lc()))
|
||||||
prefix="gated_"
|
connection.append((self.prefix+"tri_en_bar", self.tri_gate_array_inst.get_pin("en_bar").lc()))
|
||||||
else:
|
connection.append((self.prefix+"tri_en", self.tri_gate_array_inst.get_pin("en").lc()))
|
||||||
prefix=""
|
connection.append((self.prefix+"clk_bar", self.precharge_array_inst.get_pin("en").lc()))
|
||||||
connection.append((prefix+"clk_bar", self.msf_data_in_inst.get_pin("clk").lc()))
|
connection.append((self.prefix+"w_en", self.write_driver_array_inst.get_pin("en").lc()))
|
||||||
connection.append((prefix+"tri_en_bar", self.tri_gate_array_inst.get_pin("en_bar").lc()))
|
connection.append((self.prefix+"s_en", self.sense_amp_array_inst.get_pin("en").lc()))
|
||||||
connection.append((prefix+"tri_en", self.tri_gate_array_inst.get_pin("en").lc()))
|
|
||||||
connection.append((prefix+"clk_bar", self.precharge_array_inst.get_pin("en").lc()))
|
|
||||||
connection.append((prefix+"w_en", self.write_driver_array_inst.get_pin("en").lc()))
|
|
||||||
connection.append((prefix+"s_en", self.sense_amp_array_inst.get_pin("en").lc()))
|
|
||||||
|
|
||||||
for (control_signal, pin_position) in connection:
|
for (control_signal, pin_position) in connection:
|
||||||
control_x_offset = self.central_line_xoffset[control_signal] + self.m2_width
|
control_x_offset = self.central_line_xoffset[control_signal] + self.m2_width
|
||||||
|
|
@ -1040,143 +1116,28 @@ class bank(design.design):
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
# clk to msf address
|
# clk to msf address
|
||||||
control_signal = prefix+"clk"
|
control_signal = self.prefix+"clk"
|
||||||
pin_position = self.msf_address_inst.get_pin("clk").uc()
|
pin_position = self.msf_address_inst.get_pin("clk").uc()
|
||||||
mid_position = pin_position + vector(0,self.m1_pitch)
|
mid_position = pin_position + vector(0,self.m1_pitch)
|
||||||
control_x_offset = self.central_line_xoffset[control_signal]
|
control_x_offset = self.central_line_xoffset[control_signal]
|
||||||
control_position = vector(control_x_offset + drc["minwidth_metal1"], mid_position.y)
|
control_position = vector(control_x_offset + self.m1_width, mid_position.y)
|
||||||
self.add_path("metal1",[pin_position, mid_position, control_position])
|
self.add_path("metal1",[pin_position, mid_position, control_position])
|
||||||
control_via_position = vector(control_x_offset, mid_position.y-0.5*drc["minwidth_metal2"])
|
control_via_position = vector(control_x_offset, mid_position.y-0.5*drc["minwidth_metal2"])
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=control_via_position)
|
offset=control_via_position)
|
||||||
|
|
||||||
# clk to wordline_driver
|
# clk to wordline_driver
|
||||||
control_signal = prefix+"clk"
|
control_signal = self.prefix+"clk"
|
||||||
pin_position = self.wordline_driver_inst.get_pin("en").uc()
|
pin_position = self.wordline_driver_inst.get_pin("en").uc()
|
||||||
mid_position = pin_position + vector(0,self.m1_pitch)
|
mid_position = pin_position + vector(0,self.m1_pitch)
|
||||||
control_x_offset = self.central_line_xoffset[control_signal]
|
control_x_offset = self.central_line_xoffset[control_signal]
|
||||||
control_position = vector(control_x_offset + drc["minwidth_metal1"], mid_position.y)
|
control_position = vector(control_x_offset + self.m1_width, mid_position.y)
|
||||||
self.add_wire(("metal1","via1","metal2"),[pin_position, mid_position, control_position])
|
self.add_wire(("metal1","via1","metal2"),[pin_position, mid_position, control_position])
|
||||||
control_via_position = vector(control_x_offset, mid_position.y-0.5*drc["minwidth_metal2"])
|
control_via_position = vector(control_x_offset, mid_position.y-0.5*drc["minwidth_metal2"])
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=control_via_position)
|
offset=control_via_position)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def route_bank_select(self):
|
|
||||||
""" Route array of or gates to gate the control signals in case
|
|
||||||
of multiple banks are created in upper level SRAM module """
|
|
||||||
return
|
|
||||||
bank_select_line_xoffset = (self.bank_select_or_position.x
|
|
||||||
- 3*drc["minwidth_metal2"])
|
|
||||||
self.add_rect(layer="metal2",
|
|
||||||
offset=[bank_select_line_xoffset,
|
|
||||||
self.bank_select_or_position.y],
|
|
||||||
width=drc["minwidth_metal2"],
|
|
||||||
height=self.num_control_lines*self.inv.height)
|
|
||||||
|
|
||||||
# bank select inverter routing
|
|
||||||
# output side
|
|
||||||
start = self.bank_select_inv_position + self.inv4x.Z_position
|
|
||||||
end = self.bank_select_or_position + self.nor2.B_position
|
|
||||||
mid = vector(start.x, end.y)
|
|
||||||
self.add_path("metal1", [start, mid, end])
|
|
||||||
|
|
||||||
# input side
|
|
||||||
start = self.bank_select_inv_position + self.inv4x.A_position
|
|
||||||
end = vector(self.left_vdd_x_offset, start.y + 3 * drc["minwidth_metal3"])
|
|
||||||
mid = vector(start.x, end.y)
|
|
||||||
self.add_wire(("metal2", "via1", "metal1"), [start, mid, end])
|
|
||||||
|
|
||||||
# save position
|
|
||||||
self.bank_select_position = end - vector(0, 0.5 * drc["minwidth_metal2"])
|
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=self.bank_select_position)
|
|
||||||
|
|
||||||
x_offset = (self.bank_select_or_position.x + self.nor2.width
|
|
||||||
+ self.inv4x.width - drc["minwidth_metal1"])
|
|
||||||
for i in range(self.num_control_lines):
|
|
||||||
base = self.bank_select_or_position.y + self.inv.height * i
|
|
||||||
if(i % 2):
|
|
||||||
Z_y_offset = (base + self.inv.height - self.inv4x.Z_position.y
|
|
||||||
- drc["minwidth_metal1"])
|
|
||||||
B_y_offset = (base + self.inv.height - self.nor2.B_position.y
|
|
||||||
- 0.5 * drc["minwidth_metal1"])
|
|
||||||
A_y_offset = (base + self.inv.height - self.nor2.A_position.y
|
|
||||||
- 0.5 * drc["minwidth_metal1"])
|
|
||||||
else:
|
|
||||||
Z_y_offset = (base + self.inv4x.Z_position.y)
|
|
||||||
B_y_offset = (base + self.nor2.B_position.y
|
|
||||||
- 0.5 * drc["minwidth_metal1"])
|
|
||||||
A_y_offset = (base + self.nor2.A_position.y
|
|
||||||
+ 0.5 * drc["minwidth_metal1"]
|
|
||||||
- self.m1m2_via.width)
|
|
||||||
|
|
||||||
# output
|
|
||||||
self.add_rect(layer="metal3",
|
|
||||||
offset=[x_offset, Z_y_offset],
|
|
||||||
width=self.central_line_xoffset[i] - x_offset,
|
|
||||||
height=drc["minwidth_metal3"])
|
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
||||||
offset=[x_offset, Z_y_offset])
|
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=[x_offset, Z_y_offset])
|
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=[self.central_line_xoffset[i], Z_y_offset])
|
|
||||||
|
|
||||||
# B_input
|
|
||||||
if i != 5:
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=[bank_select_line_xoffset, B_y_offset],
|
|
||||||
width=(self.bank_select_or_position.x
|
|
||||||
- bank_select_line_xoffset),
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
||||||
offset=[bank_select_line_xoffset, B_y_offset])
|
|
||||||
|
|
||||||
# A_input
|
|
||||||
if i != 3:
|
|
||||||
self.add_rect(layer="metal3",
|
|
||||||
offset=[self.left_vdd_x_offset, A_y_offset],
|
|
||||||
width=(self.bank_select_or_position.x
|
|
||||||
- self.left_vdd_x_offset),
|
|
||||||
height=drc["minwidth_metal3"])
|
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
||||||
offset=[self.bank_select_or_position.x
|
|
||||||
+ drc["minwidth_metal1"],
|
|
||||||
A_y_offset],
|
|
||||||
rotate=90)
|
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=[self.bank_select_or_position.x
|
|
||||||
+ drc["minwidth_metal1"],
|
|
||||||
A_y_offset],
|
|
||||||
rotate=90)
|
|
||||||
else:
|
|
||||||
# connect A to last A, both are tri_en_bar
|
|
||||||
via_offset = vector(self.bank_select_or_position.x
|
|
||||||
+ drc["minwidth_metal1"],
|
|
||||||
A_y_offset)
|
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
||||||
offset=via_offset,
|
|
||||||
rotate=90)
|
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=via_offset,
|
|
||||||
rotate=90)
|
|
||||||
|
|
||||||
start = via_offset + vector(0, 0.5 * self.m1m2_via.width)
|
|
||||||
mid = [self.left_vdd_x_offset - self.left_vdd_x_offset
|
|
||||||
- drc["minwidth_metal2"] - drc["metal2_to_metal2"]
|
|
||||||
+ bank_select_line_xoffset,
|
|
||||||
start.y]
|
|
||||||
correct_y = (2 * self.nor2.A_position.y + drc["minwidth_metal1"]
|
|
||||||
- self.m1m2_via.width)
|
|
||||||
end = start + vector(0, correct_y)
|
|
||||||
self.add_wire(("metal3", "via2", "metal2"), [start, mid, end])
|
|
||||||
|
|
||||||
# Save position
|
|
||||||
setattr(self,"{0}_position".format(self.control_signals[i]),
|
|
||||||
[self.left_vdd_x_offset, A_y_offset])
|
|
||||||
|
|
||||||
def route_vdd_supply(self):
|
def route_vdd_supply(self):
|
||||||
""" Route vdd for the precharge, sense amp, write_driver, data FF, tristate """
|
""" Route vdd for the precharge, sense amp, write_driver, data FF, tristate """
|
||||||
|
|
||||||
|
|
@ -1187,22 +1148,8 @@ class bank(design.design):
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
offset=vdd_pin.ll(),
|
offset=vdd_pin.ll(),
|
||||||
width=self.right_vdd_x_offset - vdd_pin.lx(),
|
width=self.right_vdd_x_offset - vdd_pin.lx(),
|
||||||
height=drc["minwidth_metal1"])
|
height=self.m1_width)
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
# Connect bank_select_and2_array vdd
|
|
||||||
if(self.num_banks > 1):
|
|
||||||
for i in range(self.num_control_lines):
|
|
||||||
if(i % 2):
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=[self.left_vdd_x_offset,
|
|
||||||
self.bank_select_or_position.y
|
|
||||||
+ i * self.inv.height
|
|
||||||
- 0.5 * drc["minwidth_metal1"]],
|
|
||||||
width=(self.bank_select_or_position.x
|
|
||||||
- self.left_vdd_x_offset),
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
|
|
||||||
def route_gnd_supply(self):
|
def route_gnd_supply(self):
|
||||||
""" Route gnd for the precharge, sense amp, write_driver, data FF, tristate """
|
""" Route gnd for the precharge, sense amp, write_driver, data FF, tristate """
|
||||||
|
|
@ -1220,49 +1167,24 @@ class bank(design.design):
|
||||||
offset=contact_offset,
|
offset=contact_offset,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
|
|
||||||
# Connect bank_select_or2_array gnd
|
|
||||||
if(self.num_banks > 1):
|
|
||||||
return
|
|
||||||
self.bank_select_inv_position
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=(self.bank_select_inv_position
|
|
||||||
+ self.inv4x.gnd_position),
|
|
||||||
width=(self.bank_select_or_position.x
|
|
||||||
- self.bank_select_inv_position.x),
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
|
|
||||||
x_offset = (self.bank_select_or_position.x
|
|
||||||
+ self.nor2.width + self.inv4x.width)
|
|
||||||
for i in range(self.num_control_lines):
|
|
||||||
if(i % 2 == 0):
|
|
||||||
y_offset = self.bank_select_or_position.y + i*self.inv.height \
|
|
||||||
- 0.5*drc["minwidth_metal1"]
|
|
||||||
#both M1 & M2 are horizontal, cannot be replaced with wire
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=[x_offset, y_offset],
|
|
||||||
width=drc["minwidth_metal1"],
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
self.add_rect(layer="metal2",
|
|
||||||
offset=[x_offset, y_offset],
|
|
||||||
width=self.left_gnd_x_offset \
|
|
||||||
- x_offset + self.power_rail_width,
|
|
||||||
height=drc["minwidth_metal2"])
|
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
||||||
offset=[x_offset + drc["minwidth_metal1"],
|
|
||||||
y_offset],
|
|
||||||
rotate=90)
|
|
||||||
|
|
||||||
def add_control_pins(self):
|
def add_control_pins(self):
|
||||||
""" Add the control signal input pins """
|
""" Add the control signal input pins """
|
||||||
|
|
||||||
for ctrl in self.control_signals:
|
for ctrl in self.control_signals:
|
||||||
x_offset = self.central_line_xoffset[ctrl]
|
x_offset = self.central_line_xoffset[ctrl]
|
||||||
self.add_layout_pin(text=ctrl,
|
if self.num_banks > 1:
|
||||||
layer="metal2",
|
# it's not an input pin if we have multiple banks
|
||||||
offset=vector(x_offset, self.min_point),
|
self.add_label_pin(text=ctrl,
|
||||||
width=self.m2_width,
|
layer="metal2",
|
||||||
height=self.height)
|
offset=vector(x_offset, self.min_point),
|
||||||
|
width=self.m2_width,
|
||||||
|
height=self.height)
|
||||||
|
else:
|
||||||
|
self.add_layout_pin(text=ctrl,
|
||||||
|
layer="metal2",
|
||||||
|
offset=vector(x_offset, self.min_point),
|
||||||
|
width=self.m2_width,
|
||||||
|
height=self.height)
|
||||||
|
|
||||||
|
|
||||||
def connect_rail_from_right(self,inst, pin, rail):
|
def connect_rail_from_right(self,inst, pin, rail):
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,10 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def create_modules(self):
|
def create_modules(self):
|
||||||
""" add all the required modules """
|
""" add all the required modules """
|
||||||
input_lst =["csb","web","oeb"]
|
input_lst =["csb","web","oeb","clk"]
|
||||||
output_lst = ["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar"]
|
output_lst = ["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"]
|
||||||
clk =["clk"]
|
|
||||||
rails = ["vdd", "gnd"]
|
rails = ["vdd", "gnd"]
|
||||||
for pin in input_lst + output_lst + clk + rails:
|
for pin in input_lst + output_lst + rails:
|
||||||
self.add_pin(pin)
|
self.add_pin(pin)
|
||||||
|
|
||||||
self.nand2 = nand_2()
|
self.nand2 = nand_2()
|
||||||
|
|
@ -153,9 +152,10 @@ class control_logic(design.design):
|
||||||
rotate=270)
|
rotate=270)
|
||||||
# don't change this order. This pins are meant for internal connection of msf array inside the control logic.
|
# don't change this order. This pins are meant for internal connection of msf array inside the control logic.
|
||||||
# These pins are connecting the msf_array inside of control_logic.
|
# These pins are connecting the msf_array inside of control_logic.
|
||||||
temp = ["oeb", "oe_bar", "oe",
|
temp = ["oeb", "csb", "web",
|
||||||
"csb", "cs_bar", "cs",
|
"oe_bar", "oe",
|
||||||
"web", "we_bar", "we",
|
"cs_bar", "cs",
|
||||||
|
"we_bar", "we",
|
||||||
"clk_buf", "vdd", "gnd"]
|
"clk_buf", "vdd", "gnd"]
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
|
@ -347,7 +347,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
for i in range(self.num_rails_1):
|
for i in range(self.num_rails_1):
|
||||||
offset = vector(self.rail_1_start_x + (i+1) * self.m2_pitch,0)
|
offset = vector(self.rail_1_start_x + (i+1) * self.m2_pitch,0)
|
||||||
if self.rail_1_names[i] in ["clk_bar", "vdd", "gnd"]:
|
if self.rail_1_names[i] in ["clk_buf", "clk_bar", "vdd", "gnd"]:
|
||||||
self.add_layout_pin(text=self.rail_1_names[i],
|
self.add_layout_pin(text=self.rail_1_names[i],
|
||||||
layer="metal2",
|
layer="metal2",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -367,8 +367,10 @@ class control_logic(design.design):
|
||||||
self.connect_rail_from_left_m2m3(self.msf,"dout_bar[2]","we")
|
self.connect_rail_from_left_m2m3(self.msf,"dout_bar[2]","we")
|
||||||
|
|
||||||
# Connect the gnd and vdd of the control
|
# Connect the gnd and vdd of the control
|
||||||
gnd_pins = self.msf.get_pin("gnd")
|
gnd_pins = self.msf.get_pins("gnd")
|
||||||
for p in gnd_pins:
|
for p in gnd_pins:
|
||||||
|
if p.layer != "metal2":
|
||||||
|
continue
|
||||||
gnd_pin = p.rc()
|
gnd_pin = p.rc()
|
||||||
gnd_rail_position = vector(self.rail_1_x_offsets["gnd"], gnd_pin.y)
|
gnd_rail_position = vector(self.rail_1_x_offsets["gnd"], gnd_pin.y)
|
||||||
self.add_wire(("metal1","via1","metal2"),[gnd_pin, gnd_rail_position, gnd_rail_position - vector(0,self.m2_pitch)])
|
self.add_wire(("metal1","via1","metal2"),[gnd_pin, gnd_rail_position, gnd_rail_position - vector(0,self.m2_pitch)])
|
||||||
|
|
@ -376,9 +378,12 @@ class control_logic(design.design):
|
||||||
offset=gnd_pin + self.m1m2_via_offset,
|
offset=gnd_pin + self.m1m2_via_offset,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
vdd_pin = self.msf.get_pin("vdd").bc()
|
vdd_pins = self.msf.get_pins("vdd")
|
||||||
clk_vdd_position = vector(vdd_pin.x,self.clk_buf.get_pin("vdd").uy())
|
for p in vdd_pins:
|
||||||
self.add_path("metal1",[vdd_pin,clk_vdd_position])
|
if p.layer != "metal1":
|
||||||
|
continue
|
||||||
|
clk_vdd_position = vector(p.bc().x,self.clk_buf.get_pin("vdd").uy())
|
||||||
|
self.add_path("metal1",[p.bc(),clk_vdd_position])
|
||||||
|
|
||||||
self.rail_2_start_x = max (self.row_1_width, self.row_2_width, self.row_3_width)
|
self.rail_2_start_x = max (self.row_1_width, self.row_2_width, self.row_3_width)
|
||||||
for i in range(self.num_rails_2):
|
for i in range(self.num_rails_2):
|
||||||
|
|
@ -589,8 +594,8 @@ class control_logic(design.design):
|
||||||
|
|
||||||
|
|
||||||
# Now connect the vdd and gnd rails between the replica bitline and the control logic
|
# Now connect the vdd and gnd rails between the replica bitline and the control logic
|
||||||
(rbl_row3_gnd,rbl_row1_gnd) = self.rbl.get_pin("gnd")
|
(rbl_row3_gnd,rbl_row1_gnd) = self.rbl.get_pins("gnd")
|
||||||
(rbl_row3_vdd,rbl_row1_vdd) = self.rbl.get_pin("vdd")
|
(rbl_row3_vdd,rbl_row1_vdd) = self.rbl.get_pins("vdd")
|
||||||
|
|
||||||
self.add_path("metal1",[row1_gnd_end_offset,rbl_row1_gnd.lc()])
|
self.add_path("metal1",[row1_gnd_end_offset,rbl_row1_gnd.lc()])
|
||||||
self.add_path("metal1",[row1_vdd_end_offset,rbl_row1_vdd.lc()])
|
self.add_path("metal1",[row1_vdd_end_offset,rbl_row1_vdd.lc()])
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ class delay_chain(design.design):
|
||||||
|
|
||||||
# Use the right most parts of the gnd rails and add a U connector
|
# Use the right most parts of the gnd rails and add a U connector
|
||||||
# We still have the two gnd pins, but it is an either-or connect
|
# We still have the two gnd pins, but it is an either-or connect
|
||||||
gnd_pins = self.get_pin("gnd")
|
gnd_pins = self.get_pins("gnd")
|
||||||
gnd_start = gnd_pins[0].rc()
|
gnd_start = gnd_pins[0].rc()
|
||||||
gnd_mid1 = gnd_start + vector(2*drc["metal1_to_metal1"],0)
|
gnd_mid1 = gnd_start + vector(2*drc["metal1_to_metal1"],0)
|
||||||
gnd_end = gnd_pins[1].rc()
|
gnd_end = gnd_pins[1].rc()
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,7 @@ class instance(geometry):
|
||||||
self.offset = vector(offset).snap_to_grid()
|
self.offset = vector(offset).snap_to_grid()
|
||||||
self.mirror = mirror
|
self.mirror = mirror
|
||||||
|
|
||||||
self.boundary = [vector(0,0),vector(mod.width,mod.height)]
|
self.compute_boundary(offset,mirror,rotate)
|
||||||
self.transform(offset,mirror,rotate)
|
|
||||||
|
|
||||||
debug.info(3, "creating instance: " + self.name)
|
debug.info(3, "creating instance: " + self.name)
|
||||||
|
|
||||||
|
|
@ -65,10 +64,10 @@ class instance(geometry):
|
||||||
ur = vector(max(first[0],second[0]),max(first[1],second[1]))
|
ur = vector(max(first[0],second[0]),max(first[1],second[1]))
|
||||||
self.boundary=[ll,ur]
|
self.boundary=[ll,ur]
|
||||||
|
|
||||||
def transform(self,offset,mirror,rotate):
|
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
|
||||||
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
||||||
We must then re-find the ll and ur. The master is the cell instance. """
|
We must then re-find the ll and ur. The master is the cell instance. """
|
||||||
(ll,ur) = self.boundary
|
(ll,ur) = [vector(0,0),vector(self.mod.width,self.mod.height)]
|
||||||
if mirror=="MX":
|
if mirror=="MX":
|
||||||
ll=ll.scale(1,-1)
|
ll=ll.scale(1,-1)
|
||||||
ur=ur.scale(1,-1)
|
ur=ur.scale(1,-1)
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class layout:
|
||||||
self.height = None
|
self.height = None
|
||||||
self.insts = [] # Holds module/cell layout instances
|
self.insts = [] # Holds module/cell layout instances
|
||||||
self.objs = [] # Holds all other objects (labels, geometries, etc)
|
self.objs = [] # Holds all other objects (labels, geometries, etc)
|
||||||
self.pin_map = {} # Holds name->(vector,layer) map for all pins
|
self.pin_map = {} # Holds name->pin_layout map for all pins
|
||||||
self.visited = False # Flag for traversing the hierarchy
|
self.visited = False # Flag for traversing the hierarchy
|
||||||
|
|
||||||
self.gds_read()
|
self.gds_read()
|
||||||
|
|
@ -35,9 +35,9 @@ class layout:
|
||||||
def offset_all_coordinates(self):
|
def offset_all_coordinates(self):
|
||||||
""" This function is called after everything is placed to
|
""" This function is called after everything is placed to
|
||||||
shift the origin in the lowest left corner """
|
shift the origin in the lowest left corner """
|
||||||
coordinate = self.find_lowest_coords()
|
offset = self.find_lowest_coords()
|
||||||
self.offset_attributes(coordinate)
|
#self.offset_attributes(offset)
|
||||||
self.translate(coordinate)
|
self.translate_all(offset)
|
||||||
|
|
||||||
def get_gate_offset(self, x_offset, height, inv_num):
|
def get_gate_offset(self, x_offset, height, inv_num):
|
||||||
"""Gets the base offset and y orientation of stacked rows of gates
|
"""Gets the base offset and y orientation of stacked rows of gates
|
||||||
|
|
@ -59,8 +59,7 @@ class layout:
|
||||||
def find_lowest_coords(self):
|
def find_lowest_coords(self):
|
||||||
"""Finds the lowest set of 2d cartesian coordinates within
|
"""Finds the lowest set of 2d cartesian coordinates within
|
||||||
this layout"""
|
this layout"""
|
||||||
#***1,000,000 number is used to avoid empty sequences errors***
|
# FIXME: don't depend on 1e9
|
||||||
# FIXME Is this hard coded value ok??
|
|
||||||
try:
|
try:
|
||||||
lowestx1 = min(rect.offset.x for rect in self.objs)
|
lowestx1 = min(rect.offset.x for rect in self.objs)
|
||||||
lowesty1 = min(rect.offset.y for rect in self.objs)
|
lowesty1 = min(rect.offset.y for rect in self.objs)
|
||||||
|
|
@ -73,47 +72,24 @@ class layout:
|
||||||
[lowestx2, lowesty2] = [1000000.0, 1000000.0]
|
[lowestx2, lowesty2] = [1000000.0, 1000000.0]
|
||||||
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
|
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
|
||||||
|
|
||||||
def offset_attributes(self, coordinate):
|
|
||||||
"""Translates all stored 2d cartesian coordinates within the
|
|
||||||
attr dictionary"""
|
|
||||||
# FIXME: This is dangerous. I think we should not do this, but explicitly
|
|
||||||
# offset the necessary coordinates.
|
|
||||||
|
|
||||||
#for attr_key, attr_val in self.attr.items():
|
def translate_all(self, offset):
|
||||||
for attr_key in dir(self):
|
"""
|
||||||
attr_val = getattr(self,attr_key)
|
Translates all objects, instances, and pins by the given (x,y) offset
|
||||||
|
"""
|
||||||
# skip the list of things as these will be offset separately
|
|
||||||
if (attr_key in ['objs','insts','mods','pins','conns','name_map']): continue
|
|
||||||
|
|
||||||
# if is a list
|
|
||||||
if isinstance(attr_val, list):
|
|
||||||
|
|
||||||
for i in range(len(attr_val)):
|
|
||||||
# each unit in the list is a list coordinates
|
|
||||||
if isinstance(attr_val[i], (list,vector)):
|
|
||||||
attr_val[i] = vector(attr_val[i] - coordinate)
|
|
||||||
# the list itself is a coordinate
|
|
||||||
else:
|
|
||||||
if len(attr_val)!=2: continue
|
|
||||||
for val in attr_val:
|
|
||||||
if not isinstance(val, (int, long, float)): continue
|
|
||||||
setattr(self,attr_key, vector(attr_val - coordinate))
|
|
||||||
break
|
|
||||||
|
|
||||||
# if is a vector coordinate
|
|
||||||
if isinstance(attr_val, vector):
|
|
||||||
setattr(self, attr_key, vector(attr_val - coordinate))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def translate(self, coordinate):
|
|
||||||
"""Translates all 2d cartesian coordinates in a layout given
|
|
||||||
the (x,y) offset"""
|
|
||||||
for obj in self.objs:
|
for obj in self.objs:
|
||||||
obj.offset = vector(obj.offset - coordinate)
|
obj.offset = vector(obj.offset - offset)
|
||||||
for inst in self.insts:
|
for inst in self.insts:
|
||||||
inst.offset = vector(inst.offset - coordinate)
|
inst.offset = vector(inst.offset - offset)
|
||||||
|
# The instances have a precomputed boundary that we need to update.
|
||||||
|
if inst.__class__.__name__ == "instance":
|
||||||
|
inst.compute_boundary(offset.scale(-1,-1))
|
||||||
|
for pin_name in self.pin_map.keys():
|
||||||
|
# All the pins are absolute coordinates that need to be updated.
|
||||||
|
pin_list = self.pin_map[pin_name]
|
||||||
|
for pin in pin_list:
|
||||||
|
pin.rect = [pin.ll() - offset, pin.ur() - offset]
|
||||||
|
|
||||||
|
|
||||||
def add_inst(self, name, mod, offset=[0,0], mirror="R0",rotate=0):
|
def add_inst(self, name, mod, offset=[0,0], mirror="R0",rotate=0):
|
||||||
"""Adds an instance of a mod to this module"""
|
"""Adds an instance of a mod to this module"""
|
||||||
|
|
@ -149,6 +125,18 @@ class layout:
|
||||||
""" Return a pin list (instead of a single pin) """
|
""" Return a pin list (instead of a single pin) """
|
||||||
return self.pin_map[text]
|
return self.pin_map[text]
|
||||||
|
|
||||||
|
def copy_layout_pin(self, instance, pin_name, new_name=""):
|
||||||
|
"""
|
||||||
|
Create a copied version of the layout pin at the current level.
|
||||||
|
You can optionally rename the pin to a new name.
|
||||||
|
"""
|
||||||
|
pins=instance.get_pins(pin_name)
|
||||||
|
for pin in pins:
|
||||||
|
if new_name=="":
|
||||||
|
new_name = pin.name
|
||||||
|
self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height())
|
||||||
|
|
||||||
|
|
||||||
def add_layout_pin(self, text, layer, offset, width=None, height=None):
|
def add_layout_pin(self, text, layer, offset, width=None, height=None):
|
||||||
"""Create a labeled pin """
|
"""Create a labeled pin """
|
||||||
if width==None:
|
if width==None:
|
||||||
|
|
|
||||||
|
|
@ -340,21 +340,21 @@ class nor_2(design.design):
|
||||||
- self.nmos1.height)
|
- self.nmos1.height)
|
||||||
self.A_loc = vector(xoffset, yoffset)
|
self.A_loc = vector(xoffset, yoffset)
|
||||||
# gate input
|
# gate input
|
||||||
offset = self.A_loc - vector(0, 0.5 * self.poly_contact.width)
|
offset = self.A_loc - vector(0, self.poly_contact.width)
|
||||||
self.add_contact(layers=("poly", "contact", "metal1"),
|
self.add_contact(layers=("poly", "contact", "metal1"),
|
||||||
offset=offset,
|
offset=offset,
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
# connect gate input to tx gate
|
# connect gate input to tx gate
|
||||||
offset = self.A_loc - vector(self.poly_contact.first_layer_position.y,
|
offset = self.A_loc - vector(self.poly_contact.first_layer_position.y,
|
||||||
0.5 * self.poly_contact.width)
|
self.poly_contact.width)
|
||||||
self.add_rect(layer="poly",
|
self.add_rect(layer="poly",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"],
|
width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"],
|
||||||
height=self.poly_contact.first_layer_width)
|
height=self.poly_contact.first_layer_width)
|
||||||
# extend the metal to the boundary of the cell
|
# extend the metal to the boundary of the cell
|
||||||
input_length = self.A_loc.x
|
input_length = self.A_loc.x
|
||||||
offset = [0, self.A_loc.y - 0.5 * drc["minwidth_metal1"]]
|
offset = [0, self.A_loc.y - drc["minwidth_metal1"]]
|
||||||
self.add_layout_pin(text="A",
|
self.add_layout_pin(text="A",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
|
||||||
|
|
@ -97,8 +97,8 @@ class pin_layout:
|
||||||
""" Upper left point """
|
""" Upper left point """
|
||||||
return vector(self.rect[0].x,self.rect[1].y)
|
return vector(self.rect[0].x,self.rect[1].y)
|
||||||
|
|
||||||
def br(self):
|
def lr(self):
|
||||||
""" Bottom right point """
|
""" Lower right point """
|
||||||
return vector(self.rect[1].x,self.rect[0].y)
|
return vector(self.rect[1].x,self.rect[0].y)
|
||||||
|
|
||||||
def ur(self):
|
def ur(self):
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,41 @@ class ptx(design.design):
|
||||||
# self.connect_fingered_poly()
|
# self.connect_fingered_poly()
|
||||||
self.offset_all_coordinates()
|
self.offset_all_coordinates()
|
||||||
|
|
||||||
|
def offset_attributes(self, coordinate):
|
||||||
|
"""Translates all stored 2d cartesian coordinates within the
|
||||||
|
attr dictionary"""
|
||||||
|
# FIXME: This is dangerous. I think we should not do this, but explicitly
|
||||||
|
# offset the necessary coordinates. It is only used in ptx for now!
|
||||||
|
|
||||||
|
for attr_key in dir(self):
|
||||||
|
attr_val = getattr(self,attr_key)
|
||||||
|
|
||||||
|
# skip the list of things as these will be offset separately
|
||||||
|
if (attr_key in ['objs','insts','mods','pins','conns','name_map']): continue
|
||||||
|
|
||||||
|
# if is a list
|
||||||
|
if isinstance(attr_val, list):
|
||||||
|
|
||||||
|
for i in range(len(attr_val)):
|
||||||
|
# each unit in the list is a list coordinates
|
||||||
|
if isinstance(attr_val[i], (list,vector)):
|
||||||
|
attr_val[i] = vector(attr_val[i] - coordinate)
|
||||||
|
# the list itself is a coordinate
|
||||||
|
else:
|
||||||
|
if len(attr_val)!=2: continue
|
||||||
|
for val in attr_val:
|
||||||
|
if not isinstance(val, (int, long, float)): continue
|
||||||
|
setattr(self,attr_key, vector(attr_val - coordinate))
|
||||||
|
break
|
||||||
|
|
||||||
|
# if is a vector coordinate
|
||||||
|
if isinstance(attr_val, vector):
|
||||||
|
setattr(self, attr_key, vector(attr_val - coordinate))
|
||||||
|
|
||||||
def offset_all_coordinates(self):
|
def offset_all_coordinates(self):
|
||||||
coordinate = self.find_lowest_coords()
|
offset = self.find_lowest_coords()
|
||||||
self.offset_attributes(coordinate)
|
self.offset_attributes(offset)
|
||||||
self.translate(coordinate)
|
self.translate_all(offset)
|
||||||
|
|
||||||
# We can do this in ptx because we have offset all modules it uses.
|
# We can do this in ptx because we have offset all modules it uses.
|
||||||
# Is this really true considering the paths that connect the src/drain?
|
# Is this really true considering the paths that connect the src/drain?
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ class replica_bitline(design.design):
|
||||||
height=self.rbl.height+self.bitcell.height+2*self.inv.width+0.5*drc["minwidth_metal1"])
|
height=self.rbl.height+self.bitcell.height+2*self.inv.width+0.5*drc["minwidth_metal1"])
|
||||||
|
|
||||||
# Connect the vdd pins of the bitcell load directly to vdd
|
# Connect the vdd pins of the bitcell load directly to vdd
|
||||||
vdd_pins = self.rbl_inst.get_pin("vdd")
|
vdd_pins = self.rbl_inst.get_pins("vdd")
|
||||||
for pin in vdd_pins:
|
for pin in vdd_pins:
|
||||||
offset = vector(vdd_start.x,pin.by())
|
offset = vector(vdd_start.x,pin.by())
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
|
|
@ -286,9 +286,9 @@ class replica_bitline(design.design):
|
||||||
offset=offset)
|
offset=offset)
|
||||||
|
|
||||||
# Connect the bitcell gnd pin to the rail
|
# Connect the bitcell gnd pin to the rail
|
||||||
gnd_pins = self.get_pin("gnd")
|
gnd_pins = self.get_pins("gnd")
|
||||||
gnd_start = self.get_pin("gnd").uc()
|
gnd_start = gnd_pins[0].uc()
|
||||||
rbl_gnd_pins = self.rbl_inst.get_pin("gnd")
|
rbl_gnd_pins = self.rbl_inst.get_pins("gnd")
|
||||||
# Find the left most rail on M2
|
# Find the left most rail on M2
|
||||||
gnd_pin = None
|
gnd_pin = None
|
||||||
for pin in rbl_gnd_pins:
|
for pin in rbl_gnd_pins:
|
||||||
|
|
@ -302,7 +302,7 @@ class replica_bitline(design.design):
|
||||||
|
|
||||||
|
|
||||||
# Add a second gnd pin to the second delay chain rail. No need for full length.
|
# Add a second gnd pin to the second delay chain rail. No need for full length.
|
||||||
dc_gnd_offset = self.dc_inst.get_pin("gnd")[1].ll()
|
dc_gnd_offset = self.dc_inst.get_pins("gnd")[1].ll()
|
||||||
self.add_layout_pin(text="gnd",
|
self.add_layout_pin(text="gnd",
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=dc_gnd_offset.scale(1,0),
|
offset=dc_gnd_offset.scale(1,0),
|
||||||
|
|
|
||||||
470
compiler/sram.py
470
compiler/sram.py
|
|
@ -44,6 +44,16 @@ class sram(design.design):
|
||||||
|
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
|
|
||||||
|
# These aren't for instantiating, but we use them to get the dimensions
|
||||||
|
self.poly_contact = contact(layer_stack=("poly", "contact", "metal1"))
|
||||||
|
self.poly_contact_offset = vector(0.5*self.poly_contact.width,0.5*self.poly_contact.height)
|
||||||
|
self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2"))
|
||||||
|
self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3"))
|
||||||
|
|
||||||
|
# M1/M2 routing pitch is based on contacted pitch
|
||||||
|
self.m1_pitch = max(self.m1m2_via.width,self.m1m2_via.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"])
|
||||||
|
self.m2_pitch = max(self.m2m3_via.width,self.m2m3_via.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"])
|
||||||
|
|
||||||
self.control_size = 6
|
self.control_size = 6
|
||||||
self.bank_to_bus_distance = 5*drc["minwidth_metal3"]
|
self.bank_to_bus_distance = 5*drc["minwidth_metal3"]
|
||||||
|
|
||||||
|
|
@ -54,6 +64,7 @@ class sram(design.design):
|
||||||
|
|
||||||
def compute_sizes(self):
|
def compute_sizes(self):
|
||||||
""" Computes the organization of the memory using bitcell size by trying to make it square."""
|
""" Computes the organization of the memory using bitcell size by trying to make it square."""
|
||||||
|
|
||||||
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
|
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
|
||||||
|
|
||||||
self.num_words_per_bank = self.num_words/self.num_banks
|
self.num_words_per_bank = self.num_words/self.num_banks
|
||||||
|
|
@ -109,33 +120,34 @@ class sram(design.design):
|
||||||
return words_per_row
|
return words_per_row
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" app pins """
|
""" Add pins for entire SRAM. """
|
||||||
|
|
||||||
for i in range(self.word_size):
|
for i in range(self.word_size):
|
||||||
self.add_pin("DATA[{0}]".format(i))
|
self.add_pin("DATA[{0}]".format(i))
|
||||||
for i in range(self.addr_size):
|
for i in range(self.addr_size):
|
||||||
self.add_pin("ADDR[{0}]".format(i))
|
self.add_pin("ADDR[{0}]".format(i))
|
||||||
for pin in ["CSb","WEb","OEb",
|
for pin in ["CSb","WEb","OEb","clk","vdd","gnd"]:
|
||||||
"clk","vdd","gnd"]:
|
|
||||||
self.add_pin(pin)
|
self.add_pin(pin)
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" Layout creation """
|
""" Layout creation """
|
||||||
|
|
||||||
self.create_modules()
|
self.create_modules()
|
||||||
self.add_modules()
|
|
||||||
self.add_routing()
|
|
||||||
|
|
||||||
def add_routing(self):
|
if self.num_banks == 1:
|
||||||
""" Route all of the modules """
|
self.add_single_bank_modules()
|
||||||
|
self.add_single_bank_pins()
|
||||||
|
self.route_single_bank()
|
||||||
|
else:
|
||||||
|
self.add_multi_bank_modules()
|
||||||
|
self.route_top_banks()
|
||||||
|
if self.num_banks > 2:
|
||||||
|
self.route_bottom_banks()
|
||||||
|
|
||||||
if (self.num_banks == 2 or self.num_banks == 4):
|
|
||||||
self.route_2or4_banks()
|
|
||||||
if (self.num_banks == 4):
|
|
||||||
self.route_4_banks()
|
|
||||||
self.route_bank_and_control()
|
|
||||||
self.route_supplies()
|
|
||||||
|
|
||||||
def create_multibank_modules(self):
|
|
||||||
|
|
||||||
|
def create_multi_bank_modules(self):
|
||||||
""" Add the multibank address flops and bank decoder """
|
""" Add the multibank address flops and bank decoder """
|
||||||
|
|
||||||
self.msf_msb_address = self.mod_ms_flop_array(name="msf_msb_address",
|
self.msf_msb_address = self.mod_ms_flop_array(name="msf_msb_address",
|
||||||
|
|
@ -165,63 +177,15 @@ class sram(design.design):
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
self.create_multibank_modules()
|
self.create_multibank_modules()
|
||||||
|
|
||||||
# These aren't for instantiating, but we use them to get the dimensions
|
|
||||||
self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2"))
|
|
||||||
self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3"))
|
|
||||||
|
|
||||||
self.bank_count = 0
|
self.bank_count = 0
|
||||||
|
|
||||||
self.sram_property = ["bank_clk_positions",
|
self.power_rail_width = self.bank.vdd_rail_width
|
||||||
"bank_clk_bar_positions",
|
self.sram_power_rail_gap = 4*self.bank.vdd_rail_width
|
||||||
"bank_tri_en_positions",
|
|
||||||
"bank_tri_en_bar_positions",
|
|
||||||
"bank_w_en_positions",
|
|
||||||
"bank_s_en_positions"]
|
|
||||||
self.bank_property = ["clk_position",
|
|
||||||
"clk_bar_position",
|
|
||||||
"tri_en_position",
|
|
||||||
"tri_en_bar_position",
|
|
||||||
"w_en_position",
|
|
||||||
"s_en_position", ]
|
|
||||||
|
|
||||||
self.bank_positions = []
|
|
||||||
|
|
||||||
self.bank_clk_positions = []
|
|
||||||
self.bank_clk_bar_positions = []
|
|
||||||
self.bank_tri_en_positions = []
|
|
||||||
self.bank_tri_en_bar_positions = []
|
|
||||||
self.bank_w_en_positions = []
|
|
||||||
self.bank_s_en_positions = []
|
|
||||||
|
|
||||||
# SRAM bank address 3D array
|
|
||||||
# 2 keys will return a x,y position pair
|
|
||||||
# example key1 = bank_index , key2 = addr_line_index will return [x,y]
|
|
||||||
self.sram_bank_adress_positions = []
|
|
||||||
|
|
||||||
# SRAM data lines 3D array
|
|
||||||
# 2 keys will return a x,y position pair
|
|
||||||
# example key1 = bank_index , key2 = data_line_index will return [x,y]
|
|
||||||
self.sram_bank_data_positions = []
|
|
||||||
|
|
||||||
# 2D array for bank_select position of banks
|
|
||||||
self.sram_bank_select_positions = []
|
|
||||||
|
|
||||||
# Bank power rail positions
|
|
||||||
self.sram_bank_right_vdd_positions = []
|
|
||||||
self.sram_bank_left_vdd_positions = []
|
|
||||||
self.sram_bank_left_gnd_positions = []
|
|
||||||
|
|
||||||
self.power_rail_width = self.bank.power_rail_width
|
|
||||||
self.sram_power_rail_gap = 4*self.power_rail_width
|
|
||||||
|
|
||||||
self.vdd_position = vector(0, 2*self.power_rail_width)
|
|
||||||
self.gnd_position = vector(0, 0)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_bank(self, position, x_flip, y_flip):
|
def add_bank(self, position, x_flip, y_flip):
|
||||||
""" add and place bank. All the pin position is also
|
""" Place a bank at the given position with orientations """
|
||||||
translated and saved for later use"""
|
|
||||||
|
|
||||||
# x_flip == 1 --> no flip in x_axis
|
# x_flip == 1 --> no flip in x_axis
|
||||||
# x_flip == -1 --> flip in x_axis
|
# x_flip == -1 --> flip in x_axis
|
||||||
|
|
@ -230,26 +194,25 @@ class sram(design.design):
|
||||||
|
|
||||||
# x_flip and y_flip are used for position translation
|
# x_flip and y_flip are used for position translation
|
||||||
|
|
||||||
bank_rotation = 180 if (x_flip == -1 and y_flip == -1) else 0
|
if x_flip == -1 and y_flip == -1:
|
||||||
bank_mirror = "R0"
|
bank_rotation = 180
|
||||||
|
else:
|
||||||
|
bank_rotation = 0
|
||||||
|
|
||||||
if(x_flip == y_flip):
|
if x_flip == y_flip:
|
||||||
bank_mirror = "R0"
|
bank_mirror = "R0"
|
||||||
elif(x_flip == -1):
|
elif x_flip == -1:
|
||||||
bank_mirror = "MX"
|
bank_mirror = "MX"
|
||||||
elif(y_flip == -1):
|
elif y_flip == -1:
|
||||||
bank_mirror = "MY"
|
bank_mirror = "MY"
|
||||||
|
else:
|
||||||
|
bank_mirror = "R0"
|
||||||
|
|
||||||
yMetalShift = drc["minwidth_metal3"] if (x_flip == -1) else 0
|
bank_inst=self.add_inst(name="bank{0}".format(self.bank_count),
|
||||||
xMetalShift = drc["minwidth_metal3"] if (y_flip == -1) else 0
|
mod=self.bank,
|
||||||
|
offset=position,
|
||||||
position=vector(position)
|
mirror=bank_mirror,
|
||||||
self.add_inst(name="bank{0}".format(self.bank_count),
|
rotate=bank_rotation)
|
||||||
mod=self.bank,
|
|
||||||
offset=position,
|
|
||||||
mirror=bank_mirror,
|
|
||||||
rotate=bank_rotation)
|
|
||||||
self.bank_positions.append(position)
|
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
for i in range(self.word_size):
|
for i in range(self.word_size):
|
||||||
|
|
@ -257,65 +220,15 @@ class sram(design.design):
|
||||||
for i in range(self.bank_addr_size):
|
for i in range(self.bank_addr_size):
|
||||||
temp.append("ADDR[{0}]".format(i))
|
temp.append("ADDR[{0}]".format(i))
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
temp.append("bank_select[{0}]".format(self.bank_count))
|
temp.append("bank_sel[{0}]".format(self.bank_count))
|
||||||
temp.extend(["s_en", "w_en", "tri_en_bar", "tri_en",
|
temp.extend(["s_en", "w_en", "tri_en_bar", "tri_en",
|
||||||
"clk_bar","clk" , "vdd", "gnd"])
|
"clk_bar","clk_buf" , "vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
# Saving control line properties
|
|
||||||
for i in range(len(self.sram_property)):
|
|
||||||
sub_mod_offset = getattr(self.bank,self.bank_property[i])
|
|
||||||
new=(position + vector(y_flip,x_flip).scale(sub_mod_offset)
|
|
||||||
- vector(xMetalShift,yMetalShift))
|
|
||||||
|
|
||||||
pos_list=getattr(self,self.sram_property[i])
|
|
||||||
if pos_list is None:
|
|
||||||
pos_list=[]
|
|
||||||
pos_list.append(new)
|
|
||||||
setattr(self,self.sram_property[i],pos_list)
|
|
||||||
|
|
||||||
# Address input lines
|
|
||||||
bank_address_positions = []
|
|
||||||
for addr_position in self.bank.address_positions:
|
|
||||||
new=(position + vector(y_flip,x_flip).scale(addr_position)
|
|
||||||
- vector(xMetalShift,yMetalShift))
|
|
||||||
bank_address_positions.append(new)
|
|
||||||
self.sram_bank_adress_positions.append(bank_address_positions)
|
|
||||||
|
|
||||||
# Bank select
|
|
||||||
if (self.num_banks > 1):
|
|
||||||
new=(position + vector(y_flip,x_flip).scale(self.bank.bank_select_position)
|
|
||||||
- vector(xMetalShift,yMetalShift))
|
|
||||||
self.sram_bank_select_positions.append(new)
|
|
||||||
|
|
||||||
# Data input lines
|
|
||||||
bank_data_positions = []
|
|
||||||
for data_position in self.bank.data_positions:
|
|
||||||
new=(position + vector(y_flip,x_flip).scale(data_position)
|
|
||||||
- vector(xMetalShift,yMetalShift))
|
|
||||||
bank_data_positions.append(new)
|
|
||||||
self.sram_bank_data_positions.append(bank_data_positions)
|
|
||||||
|
|
||||||
# VDD rails
|
|
||||||
|
|
||||||
yPowerShift = self.power_rail_width if(x_flip == -1) else 0
|
|
||||||
xPowerShift = self.power_rail_width if(y_flip == -1) else 0
|
|
||||||
|
|
||||||
# Right vdd
|
|
||||||
new=(position + vector(y_flip,x_flip).scale(self.bank.right_vdd_position)
|
|
||||||
- vector(xPowerShift,yPowerShift))
|
|
||||||
self.sram_bank_right_vdd_positions.append(new)
|
|
||||||
# left vdd
|
|
||||||
new=(position + vector(y_flip,x_flip).scale(self.bank.left_vdd_position)
|
|
||||||
- vector(xPowerShift,yPowerShift))
|
|
||||||
self.sram_bank_left_vdd_positions.append(new)
|
|
||||||
# left gnd
|
|
||||||
new=(position + vector(y_flip,x_flip).scale(self.bank.left_gnd_position)
|
|
||||||
- vector(xPowerShift,yPowerShift))
|
|
||||||
self.sram_bank_left_gnd_positions.append(new)
|
|
||||||
|
|
||||||
self.bank_count = self.bank_count + 1
|
self.bank_count = self.bank_count + 1
|
||||||
|
|
||||||
|
return bank_inst
|
||||||
|
|
||||||
# FIXME: This should be in geometry.py or it's own class since it is
|
# FIXME: This should be in geometry.py or it's own class since it is
|
||||||
# reusable
|
# reusable
|
||||||
def create_bus(self, layer, offset, bits, height, rotate):
|
def create_bus(self, layer, offset, bits, height, rotate):
|
||||||
|
|
@ -360,42 +273,54 @@ class sram(design.design):
|
||||||
|
|
||||||
def add_control_logic(self, position, rotate):
|
def add_control_logic(self, position, rotate):
|
||||||
""" Add and place control logic """
|
""" Add and place control logic """
|
||||||
self.control_position = position
|
self.control_logic_inst=self.add_inst(name="control",
|
||||||
self.add_inst(name="control",
|
mod=self.control,
|
||||||
mod=self.control,
|
offset=position,
|
||||||
offset=self.control_position,
|
rotate=rotate)
|
||||||
rotate=rotate)
|
temp = ["CSb", "WEb", "OEb", "clk", "s_en", "w_en", "tri_en",
|
||||||
temp = ["CSb", "WEb", "OEb", "s_en", "w_en", "tri_en",
|
"tri_en_bar", "clk_bar", "clk_buf", "vdd", "gnd"]
|
||||||
"tri_en_bar", "clk_bar", "clk", "vdd", "gnd"]
|
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_singlebank_modules(self):
|
def add_single_bank_modules(self):
|
||||||
""" This adds the moduels for a single bank SRAM with control
|
"""
|
||||||
logic. """
|
This adds the moduels for a single bank SRAM with control
|
||||||
self.add_bank([0, 0], 1, 1)
|
logic.
|
||||||
# FIXME: document
|
"""
|
||||||
loc = vector(- 2 * drc["minwidth_metal3"],
|
|
||||||
self.bank_positions[0].y + self.bank.decoder_position.y
|
|
||||||
+ 2 * drc["minwidth_metal3"])
|
|
||||||
self.add_control_logic(loc, 90)
|
|
||||||
|
|
||||||
self.width = self.bank.width + self.control.height + 2*drc["minwidth_metal3"]
|
# No orientation or offset
|
||||||
|
self.bank_inst = self.add_bank([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.
|
||||||
|
control_gap = 2*drc["minwidth_metal3"]
|
||||||
|
pos = vector(-control_gap,
|
||||||
|
self.bank.row_decoder_inst.by() + 2*drc["minwidth_metal3"])
|
||||||
|
self.add_control_logic(position=pos,
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
self.width = self.bank.width + self.control.height + control_gap
|
||||||
self.height = self.bank.height
|
self.height = self.bank.height
|
||||||
self.control.CSb_position.rotate_scale(-1,1)
|
|
||||||
self.CSb_position = (self.control.CSb_position.rotate_scale(-1,1)
|
|
||||||
+self.control_position)
|
|
||||||
self.OEb_position = (self.control.OEb_position.rotate_scale(-1,1)
|
|
||||||
+self.control_position)
|
|
||||||
self.WEb_position = (self.control.WEb_position.rotate_scale(-1,1)
|
|
||||||
+self.control_position)
|
|
||||||
self.clk_position = (self.control.clk_position.rotate_scale(-1,1)
|
|
||||||
+self.control_position)
|
|
||||||
for i in range(0, self.word_size):
|
|
||||||
self.add_label(text="DATA[{0}]".format(i),
|
|
||||||
layer="metal3",
|
|
||||||
offset=self.bank.data_positions[i])
|
|
||||||
|
|
||||||
def add_multibank_modules(self):
|
def add_single_bank_pins(self):
|
||||||
|
"""
|
||||||
|
Add the top-level pins for a single bank SRAM with control.
|
||||||
|
"""
|
||||||
|
|
||||||
|
for i in range(self.word_size):
|
||||||
|
self.copy_layout_pin(self.bank_inst, "DATA[{}]".format(i))
|
||||||
|
|
||||||
|
for i in range(self.addr_size):
|
||||||
|
self.copy_layout_pin(self.bank_inst, "ADDR[{}]".format(i))
|
||||||
|
|
||||||
|
for (old,new) in zip(["csb","web","oeb","clk"],["CSb","WEb","OEb","clk"]):
|
||||||
|
self.copy_layout_pin(self.control_logic_inst, old, new)
|
||||||
|
|
||||||
|
self.copy_layout_pin(self.bank_inst, "vdd")
|
||||||
|
self.copy_layout_pin(self.bank_inst, "gnd")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def add_multi_bank_modules(self):
|
||||||
""" This creates either a 2 or 4 bank SRAM with control logic
|
""" This creates either a 2 or 4 bank SRAM with control logic
|
||||||
and bank selection logic."""
|
and bank selection logic."""
|
||||||
|
|
||||||
|
|
@ -491,14 +416,13 @@ class sram(design.design):
|
||||||
temp.append("msb{0}".format(i))
|
temp.append("msb{0}".format(i))
|
||||||
temp.append("msb{0}_bar".format(i))
|
temp.append("msb{0}_bar".format(i))
|
||||||
else:
|
else:
|
||||||
temp.extend(["bank_select[1]", "bank_select[0]"])
|
temp.extend(["bank_sel[1]", "bank_sel[0]"])
|
||||||
temp.extend(["clk", "vdd", "gnd"])
|
temp.extend(["clk_buf", "vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
self.add_banks_0and1()
|
self.add_top_banks()
|
||||||
|
if self.num_banks == 4:
|
||||||
if (self.num_banks == 4):
|
self.add_bottom_banks()
|
||||||
self.add_banks_2and3()
|
|
||||||
|
|
||||||
# Extension of Vertical Rail
|
# Extension of Vertical Rail
|
||||||
self.create_bus(layer="metal2",
|
self.create_bus(layer="metal2",
|
||||||
|
|
@ -522,16 +446,7 @@ class sram(design.design):
|
||||||
offset=[self.vertical_line_positions[self.control_size + i].x,
|
offset=[self.vertical_line_positions[self.control_size + i].x,
|
||||||
self.max_point])
|
self.max_point])
|
||||||
|
|
||||||
def add_modules(self):
|
def add_top_banks(self):
|
||||||
""" add all the modules """
|
|
||||||
if (self.num_banks == 1):
|
|
||||||
self.add_singlebank_modules()
|
|
||||||
elif (self.num_banks == 2 or self.num_banks == 4):
|
|
||||||
self.add_multibank_modules()
|
|
||||||
|
|
||||||
self.add_labels()
|
|
||||||
|
|
||||||
def add_banks_0and1(self):
|
|
||||||
# Placement of bank 0
|
# Placement of bank 0
|
||||||
self.bank_position_0 = vector(self.bank_w,
|
self.bank_position_0 = vector(self.bank_w,
|
||||||
self.bank_h + self.sram_power_rail_gap)
|
self.bank_h + self.sram_power_rail_gap)
|
||||||
|
|
@ -542,7 +457,7 @@ class sram(design.design):
|
||||||
self.bank_position_1 = vector(x_off, self.bank_position_0.y)
|
self.bank_position_1 = vector(x_off, self.bank_position_0.y)
|
||||||
self.add_bank(self.bank_position_1, -1, 1)
|
self.add_bank(self.bank_position_1, -1, 1)
|
||||||
|
|
||||||
def add_banks_2and3(self):
|
def add_bottom_banks(self):
|
||||||
# Placement of bank 2
|
# Placement of bank 2
|
||||||
y_off = (self.bank_h + self.horizontal_bus_width
|
y_off = (self.bank_h + self.horizontal_bus_width
|
||||||
+2 * self.bank_to_bus_distance
|
+2 * self.bank_to_bus_distance
|
||||||
|
|
@ -564,10 +479,10 @@ class sram(design.design):
|
||||||
mod=self.msb_decoder,
|
mod=self.msb_decoder,
|
||||||
offset=self.msb_decoder_position,
|
offset=self.msb_decoder_position,
|
||||||
mirror="MY")
|
mirror="MY")
|
||||||
temp = ["msb0", "msb1", "bank_select[{0}]".format(0),
|
temp = ["msb0", "msb1"]
|
||||||
"bank_select[{0}]".format(1), "bank_select[{0}]".format(2),
|
for i in range(4):
|
||||||
"bank_select[{0}]".format(3),
|
temp.append("bank_sel[{}]".format(i))
|
||||||
"vdd", "gnd"]
|
temp.extend(["vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
self.control_position = vector(0, self.msb_decoder_position.y
|
self.control_position = vector(0, self.msb_decoder_position.y
|
||||||
|
|
@ -582,23 +497,9 @@ class sram(design.design):
|
||||||
# Max point
|
# Max point
|
||||||
self.max_point = self.msb_decoder_position.y + self.msb_decoder.height
|
self.max_point = self.msb_decoder_position.y + self.msb_decoder.height
|
||||||
|
|
||||||
def add_labels(self):
|
|
||||||
""" Add the top-level labels for control and address """
|
|
||||||
for label in ["CSb", "OEb", "WEb", "clk"]:
|
|
||||||
offset = getattr(self, label+"_position")
|
|
||||||
self.add_label(text=label,
|
|
||||||
layer="metal3",
|
|
||||||
offset=offset)
|
|
||||||
|
|
||||||
# add address label
|
def route_top_banks(self):
|
||||||
for addr_pos_lst in self.sram_bank_adress_positions:
|
""" Routing of top two banks """
|
||||||
for address, address_positions in enumerate(addr_pos_lst):
|
|
||||||
self.add_label(text="ADDR[{0}]".format(address),
|
|
||||||
layer="metal3",
|
|
||||||
offset=address_positions)
|
|
||||||
|
|
||||||
def route_2or4_banks(self):
|
|
||||||
""" Routing between bank 2 or 4 bank modules """
|
|
||||||
addr_start_index = len(self.sram_property) + (self.num_banks / 2)
|
addr_start_index = len(self.sram_property) + (self.num_banks / 2)
|
||||||
bank_select_index = addr_start_index + self.bank.addr_size
|
bank_select_index = addr_start_index + self.bank.addr_size
|
||||||
|
|
||||||
|
|
@ -652,7 +553,7 @@ class sram(design.design):
|
||||||
offset=contact_offset)
|
offset=contact_offset)
|
||||||
|
|
||||||
# Data connection on the horizontal bus
|
# Data connection on the horizontal bus
|
||||||
if (self.num_banks == 4):
|
if self.num_banks == 4:
|
||||||
data_connection_top = self.sram_bank_data_positions[2][0].y + self.m2m3_via.height
|
data_connection_top = self.sram_bank_data_positions[2][0].y + self.m2m3_via.height
|
||||||
else:
|
else:
|
||||||
data_connection_top=self.horizontal_bus_offset.y
|
data_connection_top=self.horizontal_bus_offset.y
|
||||||
|
|
@ -673,7 +574,7 @@ class sram(design.design):
|
||||||
offset=[self.sram_bank_data_positions[lower_bank_index][data_index].x,
|
offset=[self.sram_bank_data_positions[lower_bank_index][data_index].x,
|
||||||
self.horizontal_line_positions[data_index].y])
|
self.horizontal_line_positions[data_index].y])
|
||||||
|
|
||||||
def route_4_banks(self):
|
def route_bottom_banks(self):
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
lower_bank_index = i
|
lower_bank_index = i
|
||||||
upper_bank_index = i + 2
|
upper_bank_index = i + 2
|
||||||
|
|
@ -695,48 +596,55 @@ class sram(design.design):
|
||||||
height=self.sram_bank_left_gnd_positions[upper_bank_index].y \
|
height=self.sram_bank_left_gnd_positions[upper_bank_index].y \
|
||||||
- self.sram_bank_left_gnd_positions[lower_bank_index].y)
|
- self.sram_bank_left_gnd_positions[lower_bank_index].y)
|
||||||
|
|
||||||
|
def connect_rail_from_left_m2m3(self, src_pin, dest_pin):
|
||||||
|
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
|
||||||
|
in_pos = src_pin.rc()
|
||||||
|
out_pos = vector(dest_pin.cx(), in_pos.y)
|
||||||
|
self.add_wire(("metal3","via2","metal2"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
|
||||||
|
self.add_via(layers=("metal2","via2","metal3"),
|
||||||
|
offset=src_pin.lr(),
|
||||||
|
rotate=90)
|
||||||
|
|
||||||
|
def connect_rail_from_left_m2m1(self, src_pin, dest_pin):
|
||||||
|
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
|
||||||
|
in_pos = src_pin.rc()
|
||||||
|
out_pos = vector(dest_pin.cx(), in_pos.y)
|
||||||
|
self.add_wire(("metal2","via1","metal1"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
|
||||||
|
|
||||||
|
def route_single_bank(self):
|
||||||
|
""" Route a single bank SRAM """
|
||||||
|
# left pin is on the control logic, right pin is on the bank
|
||||||
|
connections = [("clk_buf", "clk"),
|
||||||
|
("tri_en_bar", "tri_en_bar"),
|
||||||
|
("tri_en", "tri_en"),
|
||||||
|
("clk_bar", "clk_bar"),
|
||||||
|
("w_en", "w_en"),
|
||||||
|
("s_en", "s_en")]
|
||||||
|
for (src,dest) in connections:
|
||||||
|
src_pin = self.control_logic_inst.get_pin(src)
|
||||||
|
dest_pin = self.bank_inst.get_pin(dest)
|
||||||
|
self.connect_rail_from_left_m2m3(src_pin, dest_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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
def route_bank_and_control(self):
|
def route_bank_and_control(self):
|
||||||
""" Routing between banks and control """
|
""" Routing between banks and control """
|
||||||
|
|
||||||
if (self.num_banks == 1):
|
if self.num_banks == 1:
|
||||||
|
pass
|
||||||
# FIXME what is this? add comments
|
elif self.num_banks == 2 or self.num_banks == 4:
|
||||||
# 5 = clk
|
|
||||||
# 4 = tri_en_bar
|
|
||||||
# 3 = tri_en
|
|
||||||
# 2 = clk_bar
|
|
||||||
# 1 = w_en
|
|
||||||
# 0 = s_en
|
|
||||||
|
|
||||||
control_side = []
|
|
||||||
control_side.append(self.control.clk_position.rotate_scale(-1, 1)
|
|
||||||
+ self.control_position)
|
|
||||||
control_side.append(self.control.clk_bar_position.rotate_scale(-1, 1)
|
|
||||||
+ self.control_position)
|
|
||||||
control_side.append(self.control.tri_en_position.rotate_scale(-1, 1)
|
|
||||||
+ self.control_position)
|
|
||||||
control_side.append(self.control.tri_en_bar_position.rotate_scale(-1, 1)
|
|
||||||
+ self.control_position)
|
|
||||||
control_side.append(self.control.w_en_position.rotate_scale(-1, 1)
|
|
||||||
+ self.control_position)
|
|
||||||
control_side.append(self.control.s_en_position.rotate_scale(-1, 1)
|
|
||||||
+ self.control_position)
|
|
||||||
|
|
||||||
bank_side = []
|
|
||||||
|
|
||||||
for attr_name in (self.sram_property):
|
|
||||||
bank_side.append(getattr(self,attr_name)[0])
|
|
||||||
|
|
||||||
for i in range(len(control_side)):
|
|
||||||
self.add_rect(layer="metal3",
|
|
||||||
offset=control_side[i],
|
|
||||||
width=bank_side[i].x - control_side[i].x,
|
|
||||||
height=drc["minwidth_metal3"])
|
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=[bank_side[i].x + drc["minwidth_metal2"],
|
|
||||||
control_side[i].y],
|
|
||||||
rotate=90)
|
|
||||||
elif (self.num_banks == 2 or self.num_banks == 4):
|
|
||||||
for i in range(self.control_size):
|
for i in range(self.control_size):
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=[self.vertical_line_positions[i].x + drc["minwidth_metal2"],
|
offset=[self.vertical_line_positions[i].x + drc["minwidth_metal2"],
|
||||||
|
|
@ -857,44 +765,8 @@ class sram(design.design):
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||||
offset=contact_pos)
|
offset=contact_pos)
|
||||||
|
|
||||||
def route_vdd_singlebank(self):
|
|
||||||
""" Route the vdd for 1 bank SRAMs """
|
|
||||||
|
|
||||||
# left vdd rail of bank
|
def route_vdd_multi_bank(self):
|
||||||
self.vdd_offset = self.bank.left_vdd_position
|
|
||||||
self.add_label(text="vdd",
|
|
||||||
layer="metal1",
|
|
||||||
offset=self.vdd_offset)
|
|
||||||
|
|
||||||
# Add label for right vdd rail bank
|
|
||||||
self.add_label(text="vdd",
|
|
||||||
layer="metal1",
|
|
||||||
offset=self.sram_bank_right_vdd_positions[0])
|
|
||||||
|
|
||||||
# control logic
|
|
||||||
self.control_vdd1_position = (self.control_position
|
|
||||||
+ self.control.vdd1_position.rotate_scale(-1, 1))
|
|
||||||
self.control_vdd2_position = (self.control_position
|
|
||||||
+ self.control.vdd2_position.rotate_scale(-1, 1))
|
|
||||||
|
|
||||||
self.add_rect(layer="metal1",
|
|
||||||
offset=self.control_vdd1_position,
|
|
||||||
width=self.vdd_offset.x
|
|
||||||
- self.control_vdd1_position.x,
|
|
||||||
height=drc["minwidth_metal1"])
|
|
||||||
|
|
||||||
self.add_rect(layer="metal2",
|
|
||||||
offset=self.control_vdd2_position,
|
|
||||||
width=self.vdd_offset.x
|
|
||||||
- self.control_vdd2_position.x,
|
|
||||||
height=drc["minwidth_metal2"])
|
|
||||||
|
|
||||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
|
||||||
offset=[self.vdd_offset.x,
|
|
||||||
self.control_vdd2_position.y],
|
|
||||||
size=(2, 1))
|
|
||||||
|
|
||||||
def route_vdd_multibank(self):
|
|
||||||
""" Route the vdd for 2 and 4 bank SRAMs """
|
""" Route the vdd for 2 and 4 bank SRAMs """
|
||||||
# VDD routing between banks
|
# VDD routing between banks
|
||||||
self.add_rect(layer="metal1",
|
self.add_rect(layer="metal1",
|
||||||
|
|
@ -1018,35 +890,8 @@ class sram(design.design):
|
||||||
self.vdd_position.y])
|
self.vdd_position.y])
|
||||||
|
|
||||||
|
|
||||||
def route_gnd_singlebank(self):
|
|
||||||
""" Route the gnd for 1 bank SRAMs """
|
|
||||||
|
|
||||||
# left gnd rail of bank
|
def route_gnd_multi_bank(self):
|
||||||
self.gnd_offset = self.bank.left_gnd_position
|
|
||||||
self.add_label(text="gnd",
|
|
||||||
layer="metal2",
|
|
||||||
offset=self.gnd_offset)
|
|
||||||
|
|
||||||
self.control_gnd_position = (self.control_position
|
|
||||||
+ self.control.gnd_position.rotate_scale(-1,1)
|
|
||||||
+ vector(drc["minwidth_metal2"],0))
|
|
||||||
|
|
||||||
self.add_rect(layer="metal3",
|
|
||||||
offset=self.control_gnd_position,
|
|
||||||
width=self.gnd_offset.x - self.control_gnd_position.x,
|
|
||||||
height=drc["minwidth_metal3"])
|
|
||||||
|
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=[self.gnd_offset.x,
|
|
||||||
self.control_gnd_position.y],
|
|
||||||
size=(2,1))
|
|
||||||
|
|
||||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
|
||||||
offset=self.control_gnd_position,
|
|
||||||
rotate=90)
|
|
||||||
|
|
||||||
|
|
||||||
def route_gnd_multibank(self):
|
|
||||||
""" Route the gnd for 2 and 4 bank SRAMs """
|
""" Route the gnd for 2 and 4 bank SRAMs """
|
||||||
self.add_rect(layer="metal2",
|
self.add_rect(layer="metal2",
|
||||||
offset=self.gnd_position,
|
offset=self.gnd_position,
|
||||||
|
|
@ -1141,13 +986,12 @@ class sram(design.design):
|
||||||
|
|
||||||
def route_supplies(self):
|
def route_supplies(self):
|
||||||
""" vdd/gnd routing of all modules """
|
""" vdd/gnd routing of all modules """
|
||||||
|
return
|
||||||
if (self.num_banks == 1):
|
if (self.num_banks == 1):
|
||||||
self.route_vdd_singlebank()
|
pass
|
||||||
self.route_gnd_singlebank()
|
|
||||||
elif (self.num_banks == 2 or self.num_banks == 4):
|
elif (self.num_banks == 2 or self.num_banks == 4):
|
||||||
self.route_vdd_multibank()
|
self.route_vdd_multi_bank()
|
||||||
self.route_gnd_multibank()
|
self.route_gnd_multi_bank()
|
||||||
else:
|
else:
|
||||||
debug.error("Incorrect number of banks.")
|
debug.error("Incorrect number of banks.")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ OPTS = globals.get_opts()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class bank_test(unittest.TestCase):
|
class multi_bank_test(unittest.TestCase):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
|
@ -25,20 +25,20 @@ class bank_test(unittest.TestCase):
|
||||||
import bank
|
import bank
|
||||||
|
|
||||||
debug.info(1, "No column mux")
|
debug.info(1, "No column mux")
|
||||||
a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=4, name="test_sram1")
|
a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=2, name="test_bank1")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Two way column mux")
|
debug.info(1, "Two way column mux")
|
||||||
a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=4, name="test_sram2")
|
a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=2, name="test_bank2")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Four way column mux")
|
debug.info(1, "Four way column mux")
|
||||||
a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=4, name="test_sram3")
|
a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="test_bank3")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# Eight way has a short circuit of one column mux select to gnd rail
|
# Eight way has a short circuit of one column mux select to gnd rail
|
||||||
# debug.info(1, "Eight way column mux")
|
# debug.info(1, "Eight way column mux")
|
||||||
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="test_sram4")
|
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="test_bank4")
|
||||||
# self.local_check(a)
|
# self.local_check(a)
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
@ -16,7 +16,7 @@ OPTS = globals.get_opts()
|
||||||
#@unittest.skip("SKIPPING 20_sram_test")
|
#@unittest.skip("SKIPPING 20_sram_test")
|
||||||
|
|
||||||
|
|
||||||
class bank_test(unittest.TestCase):
|
class single_bank_test(unittest.TestCase):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
|
@ -26,20 +26,20 @@ class bank_test(unittest.TestCase):
|
||||||
import bank
|
import bank
|
||||||
|
|
||||||
debug.info(1, "No column mux")
|
debug.info(1, "No column mux")
|
||||||
a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="test_sram1")
|
a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="test_bank1")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Two way column mux")
|
debug.info(1, "Two way column mux")
|
||||||
a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="test_sram2")
|
a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="test_bank2")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Four way column mux")
|
debug.info(1, "Four way column mux")
|
||||||
a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="test_sram3")
|
a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="test_bank3")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# Eight way has a short circuit of one column mux select to gnd rail
|
# Eight way has a short circuit of one column mux select to gnd rail
|
||||||
# debug.info(1, "Eight way column mux")
|
# debug.info(1, "Eight way column mux")
|
||||||
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="test_sram4")
|
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="test_bank4")
|
||||||
# self.local_check(a)
|
# self.local_check(a)
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
|
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
#!/usr/bin/env python2.7
|
|
||||||
"""
|
|
||||||
Run a regresion test on various srams
|
|
||||||
"""
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
from testutils import header
|
|
||||||
import sys,os
|
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
|
||||||
import globals
|
|
||||||
import debug
|
|
||||||
import calibre
|
|
||||||
|
|
||||||
OPTS = globals.get_opts()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class bank_test(unittest.TestCase):
|
|
||||||
|
|
||||||
def runTest(self):
|
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
|
||||||
# we will manually run lvs/drc
|
|
||||||
OPTS.check_lvsdrc = False
|
|
||||||
|
|
||||||
import bank
|
|
||||||
|
|
||||||
debug.info(1, "No column mux")
|
|
||||||
a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=2, name="test_sram1")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(1, "Two way column mux")
|
|
||||||
a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=2, name="test_sram2")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
debug.info(1, "Four way column mux")
|
|
||||||
a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="test_sram3")
|
|
||||||
self.local_check(a)
|
|
||||||
|
|
||||||
# Eight way has a short circuit of one column mux select to gnd rail
|
|
||||||
# debug.info(1, "Eight way column mux")
|
|
||||||
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="test_sram4")
|
|
||||||
# self.local_check(a)
|
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
|
||||||
globals.end_openram()
|
|
||||||
|
|
||||||
def local_check(self, a):
|
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
|
||||||
tempgds = OPTS.openram_temp + "temp.gds"
|
|
||||||
|
|
||||||
a.sp_write(tempspice)
|
|
||||||
a.gds_write(tempgds)
|
|
||||||
|
|
||||||
self.assertFalse(calibre.run_drc(a.name, tempgds))
|
|
||||||
self.assertFalse(calibre.run_lvs(a.name, tempgds, tempspice))
|
|
||||||
|
|
||||||
os.remove(tempspice)
|
|
||||||
os.remove(tempgds)
|
|
||||||
|
|
||||||
# reset the static duplicate name checker for unit tests
|
|
||||||
import design
|
|
||||||
design.design.name_map=[]
|
|
||||||
|
|
||||||
# instantiate a copy of the class to actually run the test
|
|
||||||
if __name__ == "__main__":
|
|
||||||
(OPTS, args) = globals.parse_args()
|
|
||||||
del sys.argv[1:]
|
|
||||||
header(__file__, OPTS.tech_name)
|
|
||||||
unittest.main()
|
|
||||||
|
|
@ -25,10 +25,22 @@ class sram_1bank_test(unittest.TestCase):
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
||||||
debug.info(1, "Testing sample 8bit, 64word SRAM, 1 bank")
|
debug.info(1, "Single bank, no column mux with control logic")
|
||||||
a = sram.sram(word_size=8, num_words=128, num_banks=1, name="test_sram1")
|
a = sram.sram(word_size=4, num_words=16, num_banks=1, name="test_sram1")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Single bank two way column mux with control logic")
|
||||||
|
a = sram.sram(word_size=4, num_words=32, num_banks=1, name="test_sram2")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Single bank, four way column mux with control logic")
|
||||||
|
a = sram.sram(word_size=4, num_words=64, num_banks=1, name="test_sram3")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
# debug.info(1, "Single bank, eight way column mux with control logic")
|
||||||
|
# a = sram.sram(word_size=2, num_words=128, num_banks=1, name="test_sram4")
|
||||||
|
# self.local_check(a)
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,22 @@ class sram_2bank_test(unittest.TestCase):
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
||||||
debug.info(1, "Testing sample 8bit, 128word SRAM, 2 banks")
|
debug.info(1, "Two bank, no column mux with control logic")
|
||||||
a = sram.sram(word_size=8, num_words=128, num_banks=2, name="test_sram1")
|
a = sram.sram(word_size=4, num_words=32, num_banks=2, name="test_sram1")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Two bank two way column mux with control logic")
|
||||||
|
a = sram.sram(word_size=4, num_words=64, num_banks=2, name="test_sram2")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Two bank, four way column mux with control logic")
|
||||||
|
a = sram.sram(word_size=4, num_words=128, num_banks=2, name="test_sram3")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
# debug.info(1, "Two bank, eight way column mux with control logic")
|
||||||
|
# a = sram.sram(word_size=2, num_words=256 num_banks=2, name="test_sram4")
|
||||||
|
# self.local_check(a)
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,22 @@ class sram_4bank_test(unittest.TestCase):
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
||||||
debug.info(1, "Testing sample 8bit, 128word SRAM, 4 banks")
|
debug.info(1, "Four bank, no column mux with control logic")
|
||||||
a = sram.sram(word_size=8, num_words=128, num_banks=4, name="test_sram1")
|
a = sram.sram(word_size=4, num_words=32, num_banks=4, name="test_sram1")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Four bank two way column mux with control logic")
|
||||||
|
a = sram.sram(word_size=4, num_words=64, num_banks=4, name="test_sram2")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Four bank, four way column mux with control logic")
|
||||||
|
a = sram.sram(word_size=4, num_words=128, num_banks=4, name="test_sram3")
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
# debug.info(1, "Four bank, eight way column mux with control logic")
|
||||||
|
# a = sram.sram(word_size=2, num_words=256, num_banks=4, name="test_sram4")
|
||||||
|
# self.local_check(a)
|
||||||
|
|
||||||
OPTS.check_lvsdrc = True
|
OPTS.check_lvsdrc = True
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue