SRAM single bank passing DRC/LVS.

This commit is contained in:
Matt Guthaus 2017-09-13 15:46:41 -07:00
parent 3ea003c367
commit d29dd03373
16 changed files with 561 additions and 805 deletions

View File

@ -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):

View File

@ -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()])

View File

@ -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()

View File

@ -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)

View File

@ -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:

View File

@ -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,

View File

@ -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):

View File

@ -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?

View File

@ -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),

View File

@ -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.")

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()