mirror of https://github.com/VLSIDA/OpenRAM.git
SRAM single bank passing DRC/LVS.
This commit is contained in:
parent
3ea003c367
commit
d29dd03373
578
compiler/bank.py
578
compiler/bank.py
|
|
@ -38,13 +38,24 @@ class bank(design.design):
|
|||
self.words_per_row = words_per_row
|
||||
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.add_pins()
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
self.add_modules()
|
||||
self.setup_layout_constraints()
|
||||
self.route_layout()
|
||||
|
||||
# Add and route the bank select logic
|
||||
if(self.num_banks > 1):
|
||||
self.add_bank_select()
|
||||
|
||||
# Can remove the following, but it helps for debug!
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
|
|
@ -61,14 +72,9 @@ class bank(design.design):
|
|||
# the signals gated_*.
|
||||
if(self.num_banks > 1):
|
||||
self.add_pin("bank_select")
|
||||
self.add_pin("s_en")
|
||||
self.add_pin("w_en")
|
||||
self.add_pin("tri_en_bar")
|
||||
self.add_pin("tri_en")
|
||||
self.add_pin("clk_bar")
|
||||
self.add_pin("clk")
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
for pin in ["s_en","w_en","tri_en_bar","tri_en",
|
||||
"clk_bar","clk","vdd","gnd"]:
|
||||
self.add_pin(pin)
|
||||
|
||||
def route_layout(self):
|
||||
""" Create routing amoung the modules """
|
||||
|
|
@ -82,12 +88,11 @@ class bank(design.design):
|
|||
self.route_msf_address()
|
||||
self.route_control_lines()
|
||||
self.add_control_pins()
|
||||
if self.num_banks > 1:
|
||||
self.route_bank_select()
|
||||
self.route_vdd_supply()
|
||||
self.route_gnd_supply()
|
||||
|
||||
#self.offset_all_coordinates()
|
||||
self.offset_all_coordinates()
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
""" Add modules. The order should not matter! """
|
||||
|
|
@ -109,8 +114,6 @@ class bank(design.design):
|
|||
self.add_row_decoder()
|
||||
self.add_wordline_driver()
|
||||
self.add_msf_address()
|
||||
if(self.num_banks > 1):
|
||||
self.add_bank_select()
|
||||
|
||||
def compute_sizes(self):
|
||||
""" Computes the required sizes to create the bank """
|
||||
|
|
@ -132,9 +135,12 @@ class bank(design.design):
|
|||
# Number of control lines in the bus
|
||||
self.num_control_lines = 6
|
||||
# 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:
|
||||
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
|
||||
if self.col_addr_size>0:
|
||||
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.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.m1_width = drc["minwidth_metal1"]
|
||||
self.m2_width = drc["minwidth_metal2"]
|
||||
self.m3_width = drc["minwidth_metal3"]
|
||||
|
||||
|
|
@ -212,13 +219,6 @@ class bank(design.design):
|
|||
self.inv = pinv()
|
||||
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
|
||||
self.metal2_extend_contact = (self.m1m2_via.second_layer_height
|
||||
- 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.via_shift = (self.m1m2_via.second_layer_width
|
||||
- self.m1m2_via.first_layer_width) / 2
|
||||
self.via_shift_offset = vector(0,self.via_shift)
|
||||
|
||||
def add_bitcell_array(self):
|
||||
""" Adding Bitcell Array """
|
||||
|
|
@ -257,7 +258,7 @@ class bank(design.design):
|
|||
for i in range(self.num_cols):
|
||||
temp.append("bl[{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)
|
||||
|
||||
def add_column_mux_array(self):
|
||||
|
|
@ -296,7 +297,7 @@ class bank(design.design):
|
|||
temp.append("bl_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)
|
||||
|
||||
def add_write_driver_array(self):
|
||||
|
|
@ -317,7 +318,7 @@ class bank(design.design):
|
|||
else:
|
||||
temp.append("bl_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)
|
||||
|
||||
def add_msf_data_in(self):
|
||||
|
|
@ -335,7 +336,7 @@ class bank(design.design):
|
|||
for i in range(self.word_size):
|
||||
temp.append("data_in[{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)
|
||||
|
||||
def add_tri_gate_array(self):
|
||||
|
|
@ -351,7 +352,7 @@ class bank(design.design):
|
|||
temp.append("data_out[{0}]".format(i))
|
||||
for i in range(self.word_size):
|
||||
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)
|
||||
|
||||
def add_row_decoder(self):
|
||||
|
|
@ -396,11 +397,7 @@ class bank(design.design):
|
|||
temp.append("dec_out[{0}]".format(i))
|
||||
for i in range(self.num_rows):
|
||||
temp.append("wl[{0}]".format(i))
|
||||
|
||||
if(self.num_banks > 1):
|
||||
temp.append("gated_clk")
|
||||
else:
|
||||
temp.append("clk")
|
||||
temp.append(self.prefix+"clk")
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
|
|
@ -429,10 +426,7 @@ class bank(design.design):
|
|||
temp.extend(["sel[1]","sel[0]"])
|
||||
else:
|
||||
temp.extend(["A[{0}]".format(i),"A_bar[{0}]".format(i)])
|
||||
if(self.num_banks > 1):
|
||||
temp.append("gated_clk")
|
||||
else:
|
||||
temp.append("clk")
|
||||
temp.append(self.prefix+"clk")
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
|
@ -440,12 +434,15 @@ class bank(design.design):
|
|||
def add_column_decoder(self):
|
||||
""" 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:
|
||||
return # This is done from the FF outputs directly
|
||||
if self.col_addr_size == 2:
|
||||
# FIXME: Should just load this rather than reference a level down
|
||||
self.col_decoder = self.decoder.pre2_4
|
||||
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
|
||||
else:
|
||||
# No error checking before?
|
||||
|
|
@ -473,103 +470,182 @@ class bank(design.design):
|
|||
NOR+INV gates to gate the control signals in case of multiple
|
||||
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
|
||||
self.bank_select_or_position = vector(-xoffset_nor, self.min_point)
|
||||
|
||||
# 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)
|
||||
|
||||
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
|
||||
self.bank_select_inv_position = vector(self.bank_select_or_position.x
|
||||
- 5 * drc["minwidth_metal2"]
|
||||
- self.inv4x.width,
|
||||
self.bank_select_inv_position = vector(xoffset_bank_sel_inv,
|
||||
self.min_point)
|
||||
self.add_inst(name="bank_select_inv",
|
||||
mod=self.inv4x,
|
||||
offset=self.bank_select_inv_position)
|
||||
self.connect_inst(["bank_select", "bank_select_bar", "vdd", "gnd"])
|
||||
# bank select inverter (must be made unique if more than one OR)
|
||||
bank_sel_inv=self.add_inst(name="bank_sel_inv",
|
||||
mod=self.inv,
|
||||
offset=[xoffset_bank_sel_inv,self.min_point])
|
||||
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
|
||||
|
||||
# bank_sel is vertical wire
|
||||
xoffset_bank_sel = xoffset_bank_sel_inv
|
||||
self.add_label_pin(text="bank_sel",
|
||||
layer="metal2",
|
||||
offset=vector(xoffset_bank_sel, self.min_point),
|
||||
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))
|
||||
|
||||
for i in range(self.numb_control_lines):
|
||||
# central control bus index
|
||||
# 5 = clk,4 = tri_en_bar,3 = tri_en,2 = clk_bar,1 = w_en,0 = s_en
|
||||
name_nor = "bank_selector_nor_{0}".format(i)
|
||||
name_inv = "bank_selector_inv_{0}".format(i)
|
||||
nor2_inv_connection_height = self.inv4x.A_position.y - self.nor2.Z_position.y + 0.5 * drc["minwidth_metal1"]
|
||||
# bank_sel_bar is vertical wire
|
||||
xoffset_bank_sel_bar = xoffset_bank_sel_inv+self.inv.width-self.m2_width
|
||||
self.add_label_pin(text="bank_sel_bar",
|
||||
layer="metal2",
|
||||
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))
|
||||
|
||||
if (i % 2):
|
||||
y_offset = self.min_point + self.inv.height*(i + 1)
|
||||
mod_dir = "MX"
|
||||
# nor2 output to inv input
|
||||
y_correct = self.nor2.Z_position.y + nor2_inv_connection_height - 0.5 * drc["minwidth_metal1"]
|
||||
|
||||
|
||||
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:
|
||||
y_offset = self.min_point + self.inv.height*i
|
||||
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:
|
||||
self.add_inst(name=name_nor,
|
||||
mod=self.nor2,
|
||||
offset=[xoffset_nor, y_offset],
|
||||
mirror=mod_dir)
|
||||
self.connect_inst(["gated_tri_en_bar",
|
||||
"bank_select_bar",
|
||||
self.control_signals[i].format(i),
|
||||
"vdd",
|
||||
"gnd"])
|
||||
# connect the metal1 layer to connect to the old inv output
|
||||
offset = connection - vector(0, 0.5*drc["minwidth_metal1"])
|
||||
self.add_rect(layer="metal1",
|
||||
offset=offset,
|
||||
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:
|
||||
self.add_inst(name=name_nor,
|
||||
mod=self.nor2,
|
||||
offset=[xoffset_nor, y_offset],
|
||||
mirror=mod_dir)
|
||||
self.connect_inst([self.gated_control_signals[i],
|
||||
"bank_select_bar",
|
||||
"net_block_nor_inv[{0}]".format(i),
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
self.add_inst(name=name_inv,
|
||||
mod=self.inv4x,
|
||||
offset=[xoffset_inv, y_offset],
|
||||
mirror=mod_dir)
|
||||
self.connect_inst(["net_block_nor_inv[{0}]".format(i),
|
||||
self.control_signals[i],
|
||||
"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"])
|
||||
mirror = ""
|
||||
|
||||
# These require OR (nor2+inv) gates since they are active low.
|
||||
# (writes occur on clk low)
|
||||
if input_name in ("clk", "tri_en_bar"):
|
||||
|
||||
if (i % 2):
|
||||
y_offset = self.min_point + self.inv.height * (i + 1)
|
||||
mod_dir = "MX"
|
||||
y_correct = (-self.nor2.Z_position.y + 0.5 * drc["minwidth_metal1"]
|
||||
- nor2_inv_connection_height)
|
||||
logic_inst=self.add_inst(name=name_nor,
|
||||
mod=self.nor2,
|
||||
offset=[xoffset_nor, y_offset],
|
||||
mirror=mirror)
|
||||
self.connect_inst([input_name,
|
||||
"bank_sel_bar",
|
||||
gated_name+"_temp_bar",
|
||||
"vdd",
|
||||
"gnd"])
|
||||
xoffset_bank_signal = xoffset_bank_sel_bar
|
||||
|
||||
|
||||
# the rest are AND (nand2+inv) gates
|
||||
else:
|
||||
y_offset = self.min_point + self.inv.height*i
|
||||
mod_dir = "R0"
|
||||
y_correct = self.nor2.Z_position.y - 0.5 * drc["minwidth_metal1"]
|
||||
# nor2 output to inv input
|
||||
connection = vector(xoffset_inv, y_offset + y_correct)
|
||||
self.add_rect(layer="metal1",
|
||||
offset=connection,
|
||||
width=drc["minwidth_metal1"],
|
||||
height=nor2_inv_connection_height)
|
||||
logic_inst=self.add_inst(name=name_nand,
|
||||
mod=self.nand2,
|
||||
offset=[xoffset_nand, y_offset],
|
||||
mirror=mirror)
|
||||
bank_sel_signal = "bank_sel"
|
||||
self.connect_inst([input_name,
|
||||
"bank_sel",
|
||||
gated_name+"_temp_bar",
|
||||
"vdd",
|
||||
"gnd"])
|
||||
xoffset_bank_signal = xoffset_bank_sel
|
||||
|
||||
# They all get inverters on the output
|
||||
inv_inst=self.add_inst(name=name_inv,
|
||||
mod=self.inv4x,
|
||||
offset=[xoffset_inv, y_offset],
|
||||
mirror=mirror)
|
||||
self.connect_inst([gated_name+"_temp_bar",
|
||||
gated_name,
|
||||
"vdd",
|
||||
"gnd"])
|
||||
|
||||
|
||||
# Connect the logic output to inverter input
|
||||
pre = logic_inst.get_pin("Z").lc()
|
||||
out_position = logic_inst.get_pin("Z").rc() + vector(0.5*self.m1_width,0)
|
||||
in_position = inv_inst.get_pin("A").lc() + vector(0.5*self.m1_width,0)
|
||||
post = inv_inst.get_pin("A").rc()
|
||||
self.add_path("metal1", [pre, out_position, in_position, post])
|
||||
|
||||
# Connect the inverter output to the central bus
|
||||
out_pin = inv_inst.get_pin("Z")
|
||||
bus_pos = vector(self.central_line_xoffset[gated_name], out_pin.rc().y)
|
||||
self.add_path("metal3",[out_pin.rc(), bus_pos])
|
||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||
offset=bus_pos - vector(0,0.5*self.m2m3_via.height))
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
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):
|
||||
""" Calculating layout constraints, width, height etc """
|
||||
|
|
@ -580,13 +656,17 @@ class bank(design.design):
|
|||
# Leave room for the output below the tri gate.
|
||||
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
|
||||
|
||||
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:
|
||||
decoder_min_point = 0
|
||||
self.min_point = min(tri_gate_min_point, addr_min_point, decoder_min_point)
|
||||
self.decoder_min_point = addr_min_point
|
||||
|
||||
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
|
||||
self.max_point = self.precharge_array_inst.uy()
|
||||
|
|
@ -594,7 +674,7 @@ class bank(design.design):
|
|||
self.height = self.max_point - self.min_point
|
||||
|
||||
# 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)
|
||||
self.add_layout_pin(text="vdd",
|
||||
layer="metal1",
|
||||
|
|
@ -603,7 +683,7 @@ class bank(design.design):
|
|||
height=self.height)
|
||||
|
||||
# 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)
|
||||
self.add_layout_pin(text="vdd",
|
||||
layer="metal1",
|
||||
|
|
@ -640,7 +720,7 @@ class bank(design.design):
|
|||
height=self.height)
|
||||
|
||||
# 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):
|
||||
x_offset = self.start_of_left_central_bus + i * self.m2_pitch
|
||||
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.
|
||||
self.add_label_pin(text=name,
|
||||
layer="metal2",
|
||||
offset=vector(x_offset, self.min_point),
|
||||
offset=vector(x_offset, self.decoder_min_point),
|
||||
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)
|
||||
# goes from 0 down to the min point
|
||||
|
|
@ -662,9 +742,9 @@ class bank(design.design):
|
|||
# Add a label pin for LVS correspondence
|
||||
self.add_label_pin(text=name,
|
||||
layer="metal2",
|
||||
offset=vector(x_offset, self.min_point),
|
||||
offset=vector(x_offset, self.decoder_min_point),
|
||||
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()
|
||||
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)
|
||||
|
||||
m3_min = vector([drc["minwidth_metal3"]] * 2)
|
||||
|
|
@ -734,7 +814,7 @@ class bank(design.design):
|
|||
|
||||
# Connect the address rails to the decoder
|
||||
# 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)
|
||||
self.add_path("metal1",[decoder_in_position,rail_position])
|
||||
|
||||
|
|
@ -778,8 +858,8 @@ class bank(design.design):
|
|||
for i in range(self.num_rows):
|
||||
# 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()
|
||||
decoder_out_position = self.row_decoder_inst.get_pin("decode[{}]".format(i)).rc() + vector(0.5*drc["minwidth_metal1"],0)
|
||||
driver_in_position = self.wordline_driver_inst.get_pin("in[{}]".format(i)).lc() + 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*self.m1_width,0)
|
||||
post = self.wordline_driver_inst.get_pin("in[{}]".format(i)).rc()
|
||||
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])
|
||||
|
||||
# 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"])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=selx_via)
|
||||
|
|
@ -870,7 +950,7 @@ class bank(design.design):
|
|||
mid_position = vector(in_position.x,dout_position.y)
|
||||
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()
|
||||
self.add_via(layers=("metal2", "via2", "metal3"),
|
||||
offset=dout_via,
|
||||
|
|
@ -934,7 +1014,7 @@ class bank(design.design):
|
|||
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)
|
||||
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"),
|
||||
offset=dout_via,
|
||||
rotate=90)
|
||||
|
|
@ -947,7 +1027,7 @@ class bank(design.design):
|
|||
for gnd_pin in self.msf_address_inst.get_pins("gnd"):
|
||||
if gnd_pin.layer != "metal2":
|
||||
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"),
|
||||
offset=gnd_via,
|
||||
rotate=90)
|
||||
|
|
@ -1019,16 +1099,12 @@ class bank(design.design):
|
|||
# Connection from the central bus to the main control block crosses
|
||||
# pre-decoder and this connection is in metal3
|
||||
connection = []
|
||||
if self.num_banks>1:
|
||||
prefix="gated_"
|
||||
else:
|
||||
prefix=""
|
||||
connection.append((prefix+"clk_bar", self.msf_data_in_inst.get_pin("clk").lc()))
|
||||
connection.append((prefix+"tri_en_bar", self.tri_gate_array_inst.get_pin("en_bar").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()))
|
||||
connection.append((self.prefix+"clk_bar", self.msf_data_in_inst.get_pin("clk").lc()))
|
||||
connection.append((self.prefix+"tri_en_bar", self.tri_gate_array_inst.get_pin("en_bar").lc()))
|
||||
connection.append((self.prefix+"tri_en", self.tri_gate_array_inst.get_pin("en").lc()))
|
||||
connection.append((self.prefix+"clk_bar", self.precharge_array_inst.get_pin("en").lc()))
|
||||
connection.append((self.prefix+"w_en", self.write_driver_array_inst.get_pin("en").lc()))
|
||||
connection.append((self.prefix+"s_en", self.sense_amp_array_inst.get_pin("en").lc()))
|
||||
|
||||
for (control_signal, pin_position) in connection:
|
||||
control_x_offset = self.central_line_xoffset[control_signal] + self.m2_width
|
||||
|
|
@ -1040,143 +1116,28 @@ class bank(design.design):
|
|||
rotate=90)
|
||||
|
||||
# clk to msf address
|
||||
control_signal = prefix+"clk"
|
||||
control_signal = self.prefix+"clk"
|
||||
pin_position = self.msf_address_inst.get_pin("clk").uc()
|
||||
mid_position = pin_position + vector(0,self.m1_pitch)
|
||||
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])
|
||||
control_via_position = vector(control_x_offset, mid_position.y-0.5*drc["minwidth_metal2"])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=control_via_position)
|
||||
|
||||
# clk to wordline_driver
|
||||
control_signal = prefix+"clk"
|
||||
control_signal = self.prefix+"clk"
|
||||
pin_position = self.wordline_driver_inst.get_pin("en").uc()
|
||||
mid_position = pin_position + vector(0,self.m1_pitch)
|
||||
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])
|
||||
control_via_position = vector(control_x_offset, mid_position.y-0.5*drc["minwidth_metal2"])
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
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):
|
||||
""" 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",
|
||||
offset=vdd_pin.ll(),
|
||||
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):
|
||||
""" Route gnd for the precharge, sense amp, write_driver, data FF, tristate """
|
||||
|
|
@ -1220,49 +1167,24 @@ class bank(design.design):
|
|||
offset=contact_offset,
|
||||
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):
|
||||
""" Add the control signal input pins """
|
||||
|
||||
for ctrl in self.control_signals:
|
||||
x_offset = self.central_line_xoffset[ctrl]
|
||||
self.add_layout_pin(text=ctrl,
|
||||
layer="metal2",
|
||||
offset=vector(x_offset, self.min_point),
|
||||
width=self.m2_width,
|
||||
height=self.height)
|
||||
if self.num_banks > 1:
|
||||
# it's not an input pin if we have multiple banks
|
||||
self.add_label_pin(text=ctrl,
|
||||
layer="metal2",
|
||||
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):
|
||||
|
|
|
|||
|
|
@ -34,11 +34,10 @@ class control_logic(design.design):
|
|||
|
||||
def create_modules(self):
|
||||
""" add all the required modules """
|
||||
input_lst =["csb","web","oeb"]
|
||||
output_lst = ["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar"]
|
||||
clk =["clk"]
|
||||
input_lst =["csb","web","oeb","clk"]
|
||||
output_lst = ["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"]
|
||||
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.nand2 = nand_2()
|
||||
|
|
@ -153,9 +152,10 @@ class control_logic(design.design):
|
|||
rotate=270)
|
||||
# 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.
|
||||
temp = ["oeb", "oe_bar", "oe",
|
||||
"csb", "cs_bar", "cs",
|
||||
"web", "we_bar", "we",
|
||||
temp = ["oeb", "csb", "web",
|
||||
"oe_bar", "oe",
|
||||
"cs_bar", "cs",
|
||||
"we_bar", "we",
|
||||
"clk_buf", "vdd", "gnd"]
|
||||
self.connect_inst(temp)
|
||||
|
||||
|
|
@ -347,7 +347,7 @@ class control_logic(design.design):
|
|||
|
||||
for i in range(self.num_rails_1):
|
||||
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],
|
||||
layer="metal2",
|
||||
offset=offset,
|
||||
|
|
@ -367,8 +367,10 @@ class control_logic(design.design):
|
|||
self.connect_rail_from_left_m2m3(self.msf,"dout_bar[2]","we")
|
||||
|
||||
# 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:
|
||||
if p.layer != "metal2":
|
||||
continue
|
||||
gnd_pin = p.rc()
|
||||
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)])
|
||||
|
|
@ -376,9 +378,12 @@ class control_logic(design.design):
|
|||
offset=gnd_pin + self.m1m2_via_offset,
|
||||
rotate=90)
|
||||
|
||||
vdd_pin = self.msf.get_pin("vdd").bc()
|
||||
clk_vdd_position = vector(vdd_pin.x,self.clk_buf.get_pin("vdd").uy())
|
||||
self.add_path("metal1",[vdd_pin,clk_vdd_position])
|
||||
vdd_pins = self.msf.get_pins("vdd")
|
||||
for p in vdd_pins:
|
||||
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)
|
||||
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
|
||||
(rbl_row3_gnd,rbl_row1_gnd) = self.rbl.get_pin("gnd")
|
||||
(rbl_row3_vdd,rbl_row1_vdd) = self.rbl.get_pin("vdd")
|
||||
(rbl_row3_gnd,rbl_row1_gnd) = self.rbl.get_pins("gnd")
|
||||
(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_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
|
||||
# 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_mid1 = gnd_start + vector(2*drc["metal1_to_metal1"],0)
|
||||
gnd_end = gnd_pins[1].rc()
|
||||
|
|
|
|||
|
|
@ -41,8 +41,7 @@ class instance(geometry):
|
|||
self.offset = vector(offset).snap_to_grid()
|
||||
self.mirror = mirror
|
||||
|
||||
self.boundary = [vector(0,0),vector(mod.width,mod.height)]
|
||||
self.transform(offset,mirror,rotate)
|
||||
self.compute_boundary(offset,mirror,rotate)
|
||||
|
||||
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]))
|
||||
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.
|
||||
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":
|
||||
ll=ll.scale(1,-1)
|
||||
ur=ur.scale(1,-1)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class layout:
|
|||
self.height = None
|
||||
self.insts = [] # Holds module/cell layout instances
|
||||
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.gds_read()
|
||||
|
|
@ -35,9 +35,9 @@ class layout:
|
|||
def offset_all_coordinates(self):
|
||||
""" This function is called after everything is placed to
|
||||
shift the origin in the lowest left corner """
|
||||
coordinate = self.find_lowest_coords()
|
||||
self.offset_attributes(coordinate)
|
||||
self.translate(coordinate)
|
||||
offset = self.find_lowest_coords()
|
||||
#self.offset_attributes(offset)
|
||||
self.translate_all(offset)
|
||||
|
||||
def get_gate_offset(self, x_offset, height, inv_num):
|
||||
"""Gets the base offset and y orientation of stacked rows of gates
|
||||
|
|
@ -59,8 +59,7 @@ class layout:
|
|||
def find_lowest_coords(self):
|
||||
"""Finds the lowest set of 2d cartesian coordinates within
|
||||
this layout"""
|
||||
#***1,000,000 number is used to avoid empty sequences errors***
|
||||
# FIXME Is this hard coded value ok??
|
||||
# FIXME: don't depend on 1e9
|
||||
try:
|
||||
lowestx1 = min(rect.offset.x 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]
|
||||
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():
|
||||
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 translate(self, coordinate):
|
||||
"""Translates all 2d cartesian coordinates in a layout given
|
||||
the (x,y) offset"""
|
||||
def translate_all(self, offset):
|
||||
"""
|
||||
Translates all objects, instances, and pins by the given (x,y) offset
|
||||
"""
|
||||
for obj in self.objs:
|
||||
obj.offset = vector(obj.offset - coordinate)
|
||||
obj.offset = vector(obj.offset - offset)
|
||||
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):
|
||||
"""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 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):
|
||||
"""Create a labeled pin """
|
||||
if width==None:
|
||||
|
|
|
|||
|
|
@ -340,21 +340,21 @@ class nor_2(design.design):
|
|||
- self.nmos1.height)
|
||||
self.A_loc = vector(xoffset, yoffset)
|
||||
# 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"),
|
||||
offset=offset,
|
||||
rotate=90)
|
||||
|
||||
# connect gate input to tx gate
|
||||
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",
|
||||
offset=offset,
|
||||
width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"],
|
||||
height=self.poly_contact.first_layer_width)
|
||||
# extend the metal to the boundary of the cell
|
||||
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",
|
||||
layer="metal1",
|
||||
offset=offset,
|
||||
|
|
|
|||
|
|
@ -97,8 +97,8 @@ class pin_layout:
|
|||
""" Upper left point """
|
||||
return vector(self.rect[0].x,self.rect[1].y)
|
||||
|
||||
def br(self):
|
||||
""" Bottom right point """
|
||||
def lr(self):
|
||||
""" Lower right point """
|
||||
return vector(self.rect[1].x,self.rect[0].y)
|
||||
|
||||
def ur(self):
|
||||
|
|
|
|||
|
|
@ -50,10 +50,41 @@ class ptx(design.design):
|
|||
# self.connect_fingered_poly()
|
||||
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):
|
||||
coordinate = self.find_lowest_coords()
|
||||
self.offset_attributes(coordinate)
|
||||
self.translate(coordinate)
|
||||
offset = self.find_lowest_coords()
|
||||
self.offset_attributes(offset)
|
||||
self.translate_all(offset)
|
||||
|
||||
# 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?
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
|
||||
# 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:
|
||||
offset = vector(vdd_start.x,pin.by())
|
||||
self.add_rect(layer="metal1",
|
||||
|
|
@ -286,9 +286,9 @@ class replica_bitline(design.design):
|
|||
offset=offset)
|
||||
|
||||
# Connect the bitcell gnd pin to the rail
|
||||
gnd_pins = self.get_pin("gnd")
|
||||
gnd_start = self.get_pin("gnd").uc()
|
||||
rbl_gnd_pins = self.rbl_inst.get_pin("gnd")
|
||||
gnd_pins = self.get_pins("gnd")
|
||||
gnd_start = gnd_pins[0].uc()
|
||||
rbl_gnd_pins = self.rbl_inst.get_pins("gnd")
|
||||
# Find the left most rail on M2
|
||||
gnd_pin = None
|
||||
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.
|
||||
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",
|
||||
layer="metal1",
|
||||
offset=dc_gnd_offset.scale(1,0),
|
||||
|
|
|
|||
476
compiler/sram.py
476
compiler/sram.py
|
|
@ -43,7 +43,17 @@ class sram(design.design):
|
|||
self.num_words))
|
||||
|
||||
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.bank_to_bus_distance = 5*drc["minwidth_metal3"]
|
||||
|
||||
|
|
@ -54,6 +64,7 @@ class sram(design.design):
|
|||
|
||||
def compute_sizes(self):
|
||||
""" 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.")
|
||||
|
||||
self.num_words_per_bank = self.num_words/self.num_banks
|
||||
|
|
@ -109,33 +120,34 @@ class sram(design.design):
|
|||
return words_per_row
|
||||
|
||||
def add_pins(self):
|
||||
""" app pins """
|
||||
""" Add pins for entire SRAM. """
|
||||
|
||||
for i in range(self.word_size):
|
||||
self.add_pin("DATA[{0}]".format(i))
|
||||
for i in range(self.addr_size):
|
||||
self.add_pin("ADDR[{0}]".format(i))
|
||||
for pin in ["CSb","WEb","OEb",
|
||||
"clk","vdd","gnd"]:
|
||||
for pin in ["CSb","WEb","OEb","clk","vdd","gnd"]:
|
||||
self.add_pin(pin)
|
||||
|
||||
def create_layout(self):
|
||||
""" Layout creation """
|
||||
|
||||
self.create_modules()
|
||||
self.add_modules()
|
||||
self.add_routing()
|
||||
|
||||
def add_routing(self):
|
||||
""" Route all of the modules """
|
||||
|
||||
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()
|
||||
if self.num_banks == 1:
|
||||
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()
|
||||
|
||||
def create_multibank_modules(self):
|
||||
|
||||
|
||||
|
||||
def create_multi_bank_modules(self):
|
||||
""" Add the multibank address flops and bank decoder """
|
||||
|
||||
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):
|
||||
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.sram_property = ["bank_clk_positions",
|
||||
"bank_clk_bar_positions",
|
||||
"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)
|
||||
self.power_rail_width = self.bank.vdd_rail_width
|
||||
self.sram_power_rail_gap = 4*self.bank.vdd_rail_width
|
||||
|
||||
|
||||
|
||||
def add_bank(self, position, x_flip, y_flip):
|
||||
""" add and place bank. All the pin position is also
|
||||
translated and saved for later use"""
|
||||
""" Place a bank at the given position with orientations """
|
||||
|
||||
# x_flip == 1 --> no 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
|
||||
|
||||
bank_rotation = 180 if (x_flip == -1 and y_flip == -1) else 0
|
||||
bank_mirror = "R0"
|
||||
if x_flip == -1 and y_flip == -1:
|
||||
bank_rotation = 180
|
||||
else:
|
||||
bank_rotation = 0
|
||||
|
||||
if(x_flip == y_flip):
|
||||
if x_flip == y_flip:
|
||||
bank_mirror = "R0"
|
||||
elif(x_flip == -1):
|
||||
elif x_flip == -1:
|
||||
bank_mirror = "MX"
|
||||
elif(y_flip == -1):
|
||||
elif y_flip == -1:
|
||||
bank_mirror = "MY"
|
||||
|
||||
yMetalShift = drc["minwidth_metal3"] if (x_flip == -1) else 0
|
||||
xMetalShift = drc["minwidth_metal3"] if (y_flip == -1) else 0
|
||||
|
||||
position=vector(position)
|
||||
self.add_inst(name="bank{0}".format(self.bank_count),
|
||||
mod=self.bank,
|
||||
offset=position,
|
||||
mirror=bank_mirror,
|
||||
rotate=bank_rotation)
|
||||
self.bank_positions.append(position)
|
||||
else:
|
||||
bank_mirror = "R0"
|
||||
|
||||
bank_inst=self.add_inst(name="bank{0}".format(self.bank_count),
|
||||
mod=self.bank,
|
||||
offset=position,
|
||||
mirror=bank_mirror,
|
||||
rotate=bank_rotation)
|
||||
|
||||
temp = []
|
||||
for i in range(self.word_size):
|
||||
|
|
@ -257,64 +220,14 @@ class sram(design.design):
|
|||
for i in range(self.bank_addr_size):
|
||||
temp.append("ADDR[{0}]".format(i))
|
||||
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",
|
||||
"clk_bar","clk" , "vdd", "gnd"])
|
||||
"clk_bar","clk_buf" , "vdd", "gnd"])
|
||||
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
|
||||
|
||||
return bank_inst
|
||||
|
||||
# FIXME: This should be in geometry.py or it's own class since it is
|
||||
# reusable
|
||||
|
|
@ -360,42 +273,54 @@ class sram(design.design):
|
|||
|
||||
def add_control_logic(self, position, rotate):
|
||||
""" Add and place control logic """
|
||||
self.control_position = position
|
||||
self.add_inst(name="control",
|
||||
mod=self.control,
|
||||
offset=self.control_position,
|
||||
rotate=rotate)
|
||||
temp = ["CSb", "WEb", "OEb", "s_en", "w_en", "tri_en",
|
||||
"tri_en_bar", "clk_bar", "clk", "vdd", "gnd"]
|
||||
self.control_logic_inst=self.add_inst(name="control",
|
||||
mod=self.control,
|
||||
offset=position,
|
||||
rotate=rotate)
|
||||
temp = ["CSb", "WEb", "OEb", "clk", "s_en", "w_en", "tri_en",
|
||||
"tri_en_bar", "clk_bar", "clk_buf", "vdd", "gnd"]
|
||||
self.connect_inst(temp)
|
||||
|
||||
def add_singlebank_modules(self):
|
||||
""" This adds the moduels for a single bank SRAM with control
|
||||
logic. """
|
||||
self.add_bank([0, 0], 1, 1)
|
||||
# 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)
|
||||
def add_single_bank_modules(self):
|
||||
"""
|
||||
This adds the moduels for a single bank SRAM with control
|
||||
logic.
|
||||
"""
|
||||
|
||||
# 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 + 2*drc["minwidth_metal3"]
|
||||
self.width = self.bank.width + self.control.height + control_gap
|
||||
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
|
||||
and bank selection logic."""
|
||||
|
||||
|
|
@ -491,14 +416,13 @@ class sram(design.design):
|
|||
temp.append("msb{0}".format(i))
|
||||
temp.append("msb{0}_bar".format(i))
|
||||
else:
|
||||
temp.extend(["bank_select[1]", "bank_select[0]"])
|
||||
temp.extend(["clk", "vdd", "gnd"])
|
||||
temp.extend(["bank_sel[1]", "bank_sel[0]"])
|
||||
temp.extend(["clk_buf", "vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
self.add_banks_0and1()
|
||||
|
||||
if (self.num_banks == 4):
|
||||
self.add_banks_2and3()
|
||||
self.add_top_banks()
|
||||
if self.num_banks == 4:
|
||||
self.add_bottom_banks()
|
||||
|
||||
# Extension of Vertical Rail
|
||||
self.create_bus(layer="metal2",
|
||||
|
|
@ -522,16 +446,7 @@ class sram(design.design):
|
|||
offset=[self.vertical_line_positions[self.control_size + i].x,
|
||||
self.max_point])
|
||||
|
||||
def add_modules(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):
|
||||
def add_top_banks(self):
|
||||
# Placement of bank 0
|
||||
self.bank_position_0 = vector(self.bank_w,
|
||||
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.add_bank(self.bank_position_1, -1, 1)
|
||||
|
||||
def add_banks_2and3(self):
|
||||
def add_bottom_banks(self):
|
||||
# Placement of bank 2
|
||||
y_off = (self.bank_h + self.horizontal_bus_width
|
||||
+2 * self.bank_to_bus_distance
|
||||
|
|
@ -564,10 +479,10 @@ class sram(design.design):
|
|||
mod=self.msb_decoder,
|
||||
offset=self.msb_decoder_position,
|
||||
mirror="MY")
|
||||
temp = ["msb0", "msb1", "bank_select[{0}]".format(0),
|
||||
"bank_select[{0}]".format(1), "bank_select[{0}]".format(2),
|
||||
"bank_select[{0}]".format(3),
|
||||
"vdd", "gnd"]
|
||||
temp = ["msb0", "msb1"]
|
||||
for i in range(4):
|
||||
temp.append("bank_sel[{}]".format(i))
|
||||
temp.extend(["vdd", "gnd"])
|
||||
self.connect_inst(temp)
|
||||
|
||||
self.control_position = vector(0, self.msb_decoder_position.y
|
||||
|
|
@ -582,23 +497,9 @@ class sram(design.design):
|
|||
# Max point
|
||||
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
|
||||
for addr_pos_lst in self.sram_bank_adress_positions:
|
||||
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 """
|
||||
def route_top_banks(self):
|
||||
""" Routing of top two banks """
|
||||
addr_start_index = len(self.sram_property) + (self.num_banks / 2)
|
||||
bank_select_index = addr_start_index + self.bank.addr_size
|
||||
|
||||
|
|
@ -652,7 +553,7 @@ class sram(design.design):
|
|||
offset=contact_offset)
|
||||
|
||||
# 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
|
||||
else:
|
||||
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,
|
||||
self.horizontal_line_positions[data_index].y])
|
||||
|
||||
def route_4_banks(self):
|
||||
def route_bottom_banks(self):
|
||||
for i in range(2):
|
||||
lower_bank_index = i
|
||||
upper_bank_index = i + 2
|
||||
|
|
@ -695,48 +596,55 @@ class sram(design.design):
|
|||
height=self.sram_bank_left_gnd_positions[upper_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):
|
||||
""" Routing between banks and control """
|
||||
|
||||
if (self.num_banks == 1):
|
||||
|
||||
# FIXME what is this? add comments
|
||||
# 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):
|
||||
if self.num_banks == 1:
|
||||
pass
|
||||
elif self.num_banks == 2 or self.num_banks == 4:
|
||||
for i in range(self.control_size):
|
||||
self.add_via(layers=("metal1", "via1", "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"),
|
||||
offset=contact_pos)
|
||||
|
||||
def route_vdd_singlebank(self):
|
||||
""" Route the vdd for 1 bank SRAMs """
|
||||
|
||||
# left vdd rail of bank
|
||||
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):
|
||||
def route_vdd_multi_bank(self):
|
||||
""" Route the vdd for 2 and 4 bank SRAMs """
|
||||
# VDD routing between banks
|
||||
self.add_rect(layer="metal1",
|
||||
|
|
@ -1018,35 +890,8 @@ class sram(design.design):
|
|||
self.vdd_position.y])
|
||||
|
||||
|
||||
def route_gnd_singlebank(self):
|
||||
""" Route the gnd for 1 bank SRAMs """
|
||||
|
||||
# left gnd rail of bank
|
||||
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):
|
||||
def route_gnd_multi_bank(self):
|
||||
""" Route the gnd for 2 and 4 bank SRAMs """
|
||||
self.add_rect(layer="metal2",
|
||||
offset=self.gnd_position,
|
||||
|
|
@ -1141,13 +986,12 @@ class sram(design.design):
|
|||
|
||||
def route_supplies(self):
|
||||
""" vdd/gnd routing of all modules """
|
||||
|
||||
return
|
||||
if (self.num_banks == 1):
|
||||
self.route_vdd_singlebank()
|
||||
self.route_gnd_singlebank()
|
||||
pass
|
||||
elif (self.num_banks == 2 or self.num_banks == 4):
|
||||
self.route_vdd_multibank()
|
||||
self.route_gnd_multibank()
|
||||
self.route_vdd_multi_bank()
|
||||
self.route_gnd_multi_bank()
|
||||
else:
|
||||
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):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
|
@ -25,20 +25,20 @@ class bank_test(unittest.TestCase):
|
|||
import bank
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
# 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")
|
||||
# a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="test_bank4")
|
||||
# self.local_check(a)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
|
|
@ -16,7 +16,7 @@ OPTS = globals.get_opts()
|
|||
#@unittest.skip("SKIPPING 20_sram_test")
|
||||
|
||||
|
||||
class bank_test(unittest.TestCase):
|
||||
class single_bank_test(unittest.TestCase):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
|
@ -26,20 +26,20 @@ class bank_test(unittest.TestCase):
|
|||
import bank
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
# 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=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)
|
||||
|
||||
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
|
||||
|
||||
debug.info(1, "Testing sample 8bit, 64word SRAM, 1 bank")
|
||||
a = sram.sram(word_size=8, num_words=128, num_banks=1, name="test_sram1")
|
||||
debug.info(1, "Single bank, no column mux with control logic")
|
||||
a = sram.sram(word_size=4, num_words=16, num_banks=1, name="test_sram1")
|
||||
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
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -25,10 +25,22 @@ class sram_2bank_test(unittest.TestCase):
|
|||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing sample 8bit, 128word SRAM, 2 banks")
|
||||
a = sram.sram(word_size=8, num_words=128, num_banks=2, name="test_sram1")
|
||||
debug.info(1, "Two bank, no column mux with control logic")
|
||||
a = sram.sram(word_size=4, num_words=32, num_banks=2, name="test_sram1")
|
||||
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
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -25,10 +25,22 @@ class sram_4bank_test(unittest.TestCase):
|
|||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing sample 8bit, 128word SRAM, 4 banks")
|
||||
a = sram.sram(word_size=8, num_words=128, num_banks=4, name="test_sram1")
|
||||
debug.info(1, "Four bank, no column mux with control logic")
|
||||
a = sram.sram(word_size=4, num_words=32, num_banks=4, name="test_sram1")
|
||||
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
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue