Fix 1-way single bank LVS bug. Full SRAM still not functional. 8-way has DRC error.

This commit is contained in:
Matt Guthaus 2017-09-11 14:30:52 -07:00
parent d17711c394
commit 3ea003c367
9 changed files with 197 additions and 92 deletions

View File

@ -39,13 +39,15 @@ class bank(design.design):
self.num_banks = num_banks self.num_banks = num_banks
self.compute_sizes() self.compute_sizes()
self.add_pins() self.add_pins()
self.create_modules() self.create_modules()
self.add_modules() self.add_modules()
self.setup_layout_constraints() self.setup_layout_constraints()
self.route_layout() self.route_layout()
# Can remove the following, but it helps for debug!
self.add_lvs_correspondence_points()
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
@ -56,18 +58,15 @@ class bank(design.design):
self.add_pin("ADDR[{0}]".format(i)) self.add_pin("ADDR[{0}]".format(i))
# For more than one bank, we have a bank select and name # For more than one bank, we have a bank select and name
# the signals gated_* # the signals gated_*.
if(self.num_banks > 1): if(self.num_banks > 1):
self.add_pin("bank_select") self.add_pin("bank_select")
prefix = "gated_" self.add_pin("s_en")
else: self.add_pin("w_en")
prefix = "" self.add_pin("tri_en_bar")
self.add_pin(prefix+"s_en") self.add_pin("tri_en")
self.add_pin(prefix+"w_en") self.add_pin("clk_bar")
self.add_pin(prefix+"tri_en_bar") self.add_pin("clk")
self.add_pin(prefix+"tri_en")
self.add_pin(prefix+"clk_bar")
self.add_pin(prefix+"clk")
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
@ -83,10 +82,10 @@ class bank(design.design):
self.route_msf_address() self.route_msf_address()
self.route_control_lines() self.route_control_lines()
self.add_control_pins() self.add_control_pins()
if self.num_banks > 1:
self.route_bank_select()
self.route_vdd_supply() self.route_vdd_supply()
self.route_gnd_supply() self.route_gnd_supply()
# Can remove the following, but it helps for debug!
self.add_lvs_correspondence_points()
#self.offset_all_coordinates() #self.offset_all_coordinates()
@ -110,7 +109,6 @@ class bank(design.design):
self.add_row_decoder() self.add_row_decoder()
self.add_wordline_driver() self.add_wordline_driver()
self.add_msf_address() self.add_msf_address()
if(self.num_banks > 1): if(self.num_banks > 1):
self.add_bank_select() self.add_bank_select()
@ -134,7 +132,9 @@ class bank(design.design):
# Number of control lines in the bus # Number of control lines in the bus
self.num_control_lines = 6 self.num_control_lines = 6
# The order of the control signals on the control bus: # The order of the control signals on the control bus:
self.control_lines = ["clk", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"] self.control_signals = ["clk", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"]
if self.num_banks>1:
self.control_signals = ["gated_"+str for str in self.control_signals]
# The central bus is the column address (both polarities), row address # The central bus is the column address (both polarities), row address
if self.col_addr_size>0: if self.col_addr_size>0:
self.num_addr_lines = 2**self.col_addr_size + self.row_addr_size self.num_addr_lines = 2**self.col_addr_size + self.row_addr_size
@ -159,18 +159,6 @@ class bank(design.design):
self.overall_central_bus_width = self.m2_pitch * (self.num_control_lines + self.num_addr_lines + 5) + self.gnd_rail_width self.overall_central_bus_width = self.m2_pitch * (self.num_control_lines + self.num_addr_lines + 5) + self.gnd_rail_width
# Array for control lines
self.control_signals = ["s_en",
"w_en",
"clk_bar",
"tri_en",
"tri_en_bar",
"clk"]
self.gated_control_signals = ["gated_s_en",
"gated_w_en",
"gated_clk_bar",
"gated_tri_en", "gated_tri_en_bar",
"gated_clk"]
@ -344,6 +332,7 @@ class bank(design.design):
temp = [] temp = []
for i in range(self.word_size): for i in range(self.word_size):
temp.append("DATA[{0}]".format(i)) temp.append("DATA[{0}]".format(i))
for i in range(self.word_size):
temp.append("data_in[{0}]".format(i)) temp.append("data_in[{0}]".format(i))
temp.append("data_in_bar[{0}]".format(i)) temp.append("data_in_bar[{0}]".format(i))
temp.extend(["clk_bar", "vdd", "gnd"]) temp.extend(["clk_bar", "vdd", "gnd"])
@ -484,10 +473,9 @@ class bank(design.design):
NOR+INV gates to gate the control signals in case of multiple NOR+INV gates to gate the control signals in case of multiple
banks are created in upper level SRAM module banks are created in upper level SRAM module
""" """
assert 0 xoffset_nor = self.start_of_left_central_bus + self.nor2.width + self.inv4x.width
xoffset_nor = - self.start_of_left_central_bus - self.nor2.width - self.inv4x.width
xoffset_inv = xoffset_nor + self.nor2.width xoffset_inv = xoffset_nor + self.nor2.width
self.bank_select_or_position = vector(xoffset_nor, self.min_point) self.bank_select_or_position = vector(-xoffset_nor, self.min_point)
# bank select inverter # bank select inverter
self.bank_select_inv_position = vector(self.bank_select_or_position.x self.bank_select_inv_position = vector(self.bank_select_or_position.x
@ -636,7 +624,6 @@ class bank(design.design):
def create_central_bus(self): def create_central_bus(self):
""" Create the address, supply, and control signal central bus lines. """ """ Create the address, supply, and control signal central bus lines. """
# Address lines in central line connection are 2*col_addr_size # Address lines in central line connection are 2*col_addr_size
# number of connections for the column mux (for both signal and _bar) and row_addr_size (no _bar) # number of connections for the column mux (for both signal and _bar) and row_addr_size (no _bar)
@ -645,7 +632,7 @@ class bank(design.design):
# Control lines (to the right of the GND rail) # Control lines (to the right of the GND rail)
for i in range(self.num_control_lines): for i in range(self.num_control_lines):
x_offset = self.start_of_right_central_bus + i * self.m2_pitch x_offset = self.start_of_right_central_bus + i * self.m2_pitch
self.central_line_xoffset[self.control_lines[i]]=x_offset self.central_line_xoffset[self.control_signals[i]]=x_offset
# Pins are added later if this is a single bank, so just add rectangle now # Pins are added later if this is a single bank, so just add rectangle now
self.add_rect(layer="metal2", self.add_rect(layer="metal2",
offset=vector(x_offset, self.min_point), offset=vector(x_offset, self.min_point),
@ -1032,12 +1019,16 @@ class bank(design.design):
# Connection from the central bus to the main control block crosses # Connection from the central bus to the main control block crosses
# pre-decoder and this connection is in metal3 # pre-decoder and this connection is in metal3
connection = [] connection = []
connection.append(("clk_bar", self.msf_data_in_inst.get_pin("clk").lc())) if self.num_banks>1:
connection.append(("tri_en_bar", self.tri_gate_array_inst.get_pin("en_bar").lc())) prefix="gated_"
connection.append(("tri_en", self.tri_gate_array_inst.get_pin("en").lc())) else:
connection.append(("clk_bar", self.precharge_array_inst.get_pin("clk").lc())) prefix=""
connection.append(("w_en", self.write_driver_array_inst.get_pin("wen").lc())) connection.append((prefix+"clk_bar", self.msf_data_in_inst.get_pin("clk").lc()))
connection.append(("s_en", self.sense_amp_array_inst.get_pin("sclk").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()))
for (control_signal, pin_position) in connection: for (control_signal, pin_position) in connection:
control_x_offset = self.central_line_xoffset[control_signal] + self.m2_width control_x_offset = self.central_line_xoffset[control_signal] + self.m2_width
@ -1049,7 +1040,7 @@ class bank(design.design):
rotate=90) rotate=90)
# clk to msf address # clk to msf address
control_signal = "clk" control_signal = prefix+"clk"
pin_position = self.msf_address_inst.get_pin("clk").uc() pin_position = self.msf_address_inst.get_pin("clk").uc()
mid_position = pin_position + vector(0,self.m1_pitch) mid_position = pin_position + vector(0,self.m1_pitch)
control_x_offset = self.central_line_xoffset[control_signal] control_x_offset = self.central_line_xoffset[control_signal]
@ -1060,7 +1051,7 @@ class bank(design.design):
offset=control_via_position) offset=control_via_position)
# clk to wordline_driver # clk to wordline_driver
control_signal = "clk" control_signal = prefix+"clk"
pin_position = self.wordline_driver_inst.get_pin("en").uc() pin_position = self.wordline_driver_inst.get_pin("en").uc()
mid_position = pin_position + vector(0,self.m1_pitch) mid_position = pin_position + vector(0,self.m1_pitch)
control_x_offset = self.central_line_xoffset[control_signal] control_x_offset = self.central_line_xoffset[control_signal]
@ -1072,9 +1063,10 @@ class bank(design.design):
def route_bank_select_or2_gates(self): def route_bank_select(self):
""" Route array of or gates to gate the control signals in case """ Route array of or gates to gate the control signals in case
of multiple banks are created in upper level SRAM module """ of multiple banks are created in upper level SRAM module """
return
bank_select_line_xoffset = (self.bank_select_or_position.x bank_select_line_xoffset = (self.bank_select_or_position.x
- 3*drc["minwidth_metal2"]) - 3*drc["minwidth_metal2"])
self.add_rect(layer="metal2", self.add_rect(layer="metal2",
@ -1231,6 +1223,7 @@ class bank(design.design):
# Connect bank_select_or2_array gnd # Connect bank_select_or2_array gnd
if(self.num_banks > 1): if(self.num_banks > 1):
return
self.bank_select_inv_position self.bank_select_inv_position
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=(self.bank_select_inv_position offset=(self.bank_select_inv_position
@ -1263,21 +1256,14 @@ class bank(design.design):
def add_control_pins(self): def add_control_pins(self):
""" Add the control signal input pins """ """ Add the control signal input pins """
if self.num_banks==1: for ctrl in self.control_signals:
# If we are a single bank, just add duplicate pin shapes x_offset = self.central_line_xoffset[ctrl]
# on the existing the control bus self.add_layout_pin(text=ctrl,
for ctrl in self.control_signals: layer="metal2",
x_offset = self.central_line_xoffset[ctrl] offset=vector(x_offset, self.min_point),
self.add_layout_pin(text=ctrl, width=self.m2_width,
layer="metal2", height=self.height)
offset=vector(x_offset, self.min_point),
width=self.m2_width,
height=self.height)
else:
# If we are gating the signals, they must be the inputs to the gating logic
# Then route the outputs to the control bus
self.route_bank_select_or2_gates()
pass
def connect_rail_from_right(self,inst, pin, rail): def connect_rail_from_right(self,inst, pin, rail):
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """ """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """

View File

@ -40,6 +40,7 @@ class ms_flop_array(design.design):
def add_pins(self): def add_pins(self):
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("din[{0}]".format(i)) self.add_pin("din[{0}]".format(i))
for i in range(self.word_size):
self.add_pin("dout[{0}]".format(i)) self.add_pin("dout[{0}]".format(i))
self.add_pin("dout_bar[{0}]".format(i)) self.add_pin("dout_bar[{0}]".format(i))
self.add_pin("clk") self.add_pin("clk")

View File

@ -36,7 +36,7 @@ class precharge_array(design.design):
for i in range(self.columns): for i in range(self.columns):
self.add_pin("bl[{0}]".format(i)) self.add_pin("bl[{0}]".format(i))
self.add_pin("br[{0}]".format(i)) self.add_pin("br[{0}]".format(i))
self.add_pin("clk") self.add_pin("en")
self.add_pin("vdd") self.add_pin("vdd")
def create_layout(self): def create_layout(self):
@ -48,7 +48,7 @@ class precharge_array(design.design):
width=self.width, width=self.width,
height=drc["minwidth_metal1"]) height=drc["minwidth_metal1"])
self.add_layout_pin(text="clk", self.add_layout_pin(text="en",
layer="metal1", layer="metal1",
offset=self.pc_cell.get_pin("clk").ll(), offset=self.pc_cell.get_pin("clk").ll(),
width=self.width, width=self.width,
@ -77,5 +77,5 @@ class precharge_array(design.design):
width=drc["minwidth_metal2"], width=drc["minwidth_metal2"],
height=bl_pin.height()) height=bl_pin.height())
self.connect_inst(["bl[{0}]".format(i), "br[{0}]".format(i), self.connect_inst(["bl[{0}]".format(i), "br[{0}]".format(i),
"clk", "vdd"]) "en", "vdd"])

View File

@ -37,7 +37,7 @@ class sense_amp_array(design.design):
self.add_pin("bl[{0}]".format(i)) self.add_pin("bl[{0}]".format(i))
self.add_pin("br[{0}]".format(i)) self.add_pin("br[{0}]".format(i))
self.add_pin("sclk") self.add_pin("en")
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
@ -69,7 +69,7 @@ class sense_amp_array(design.design):
offset=amp_position) offset=amp_position)
self.connect_inst(["bl[{0}]".format(i),"br[{0}]".format(i), self.connect_inst(["bl[{0}]".format(i),"br[{0}]".format(i),
"data[{0}]".format(i/self.words_per_row), "data[{0}]".format(i/self.words_per_row),
"sclk", "vdd", "gnd"]) "en", "vdd", "gnd"])
self.add_layout_pin(text="bl[{0}]".format(i), self.add_layout_pin(text="bl[{0}]".format(i),
layer="metal2", layer="metal2",
@ -111,7 +111,7 @@ class sense_amp_array(design.design):
# add sclk rail across entire array # add sclk rail across entire array
sclk_offset = self.amp.get_pin("SCLK").ll().scale(0,1) sclk_offset = self.amp.get_pin("SCLK").ll().scale(0,1)
self.add_layout_pin(text="sclk", self.add_layout_pin(text="en",
layer="metal1", layer="metal1",
offset=sclk_offset, offset=sclk_offset,
width=self.width, width=self.width,

View File

@ -0,0 +1,69 @@
#!/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=4, 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=4, 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=4, 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

@ -0,0 +1,69 @@
#!/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

@ -49,16 +49,10 @@ class tri_gate_array(design.design):
self.tri_inst = {} self.tri_inst = {}
for i in range(0,self.columns,self.words_per_row): for i in range(0,self.columns,self.words_per_row):
name = "Xtri_gate{0}".format(i) name = "Xtri_gate{0}".format(i)
if (i % 2 == 0 or self.words_per_row > 1): base = vector(i*self.tri.width, 0)
base = vector(i*self.tri.width, 0)
mirror = "R0"
else:
base = vector((i+1)*self.tri.width, 0)
mirror = "MY"
self.tri_inst[i]=self.add_inst(name=name, self.tri_inst[i]=self.add_inst(name=name,
mod=self.tri, mod=self.tri,
offset=base, offset=base)
mirror=mirror)
self.connect_inst(["in[{0}]".format(i/self.words_per_row), self.connect_inst(["in[{0}]".format(i/self.words_per_row),
"out[{0}]".format(i/self.words_per_row), "out[{0}]".format(i/self.words_per_row),
"en", "en_bar", "vdd", "gnd"]) "en", "en_bar", "vdd", "gnd"])
@ -68,15 +62,6 @@ class tri_gate_array(design.design):
for i in range(0,self.columns,self.words_per_row): for i in range(0,self.columns,self.words_per_row):
# Avoid duplicate pins by only doing even columns
for gnd_pin in self.tri_inst[i].get_pins("gnd"):
if i%2 == 0 and gnd_pin.layer=="metal2":
self.add_layout_pin(text="gnd",
layer="metal2",
offset=gnd_pin.ll(),
width=gnd_pin.width(),
height=gnd_pin.height())
in_pin = self.tri_inst[i].get_pin("in") in_pin = self.tri_inst[i].get_pin("in")
self.add_layout_pin(text="in[{0}]".format(i/self.words_per_row), self.add_layout_pin(text="in[{0}]".format(i/self.words_per_row),
layer="metal2", layer="metal2",

View File

@ -37,7 +37,7 @@ class write_driver_array(design.design):
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("bl_out[{0}]".format(i)) self.add_pin("bl_out[{0}]".format(i))
self.add_pin("br_out[{0}]".format(i)) self.add_pin("br_out[{0}]".format(i))
self.add_pin("wen") self.add_pin("en")
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
@ -50,21 +50,16 @@ class write_driver_array(design.design):
self.driver_insts = {} self.driver_insts = {}
for i in range(0,self.columns,self.words_per_row): for i in range(0,self.columns,self.words_per_row):
name = "Xwrite_driver{}".format(i) name = "Xwrite_driver{}".format(i)
if (i % 2 == 0 or self.words_per_row>1): base = vector(i * self.driver.width,0)
base = vector(i * self.driver.width,0)
mirror = "R0"
else:
base = vector((i+1) * self.driver.width,0)
mirror = "MY"
self.driver_insts[i/self.words_per_row]=self.add_inst(name=name, self.driver_insts[i/self.words_per_row]=self.add_inst(name=name,
mod=self.driver, mod=self.driver,
offset=base, offset=base)
mirror=mirror)
self.connect_inst(["data[{0}]".format(i/self.words_per_row), self.connect_inst(["data[{0}]".format(i/self.words_per_row),
"bl_out[{0}]".format(i/self.words_per_row), "bl_out[{0}]".format(i/self.words_per_row),
"br_out[{0}]".format(i/self.words_per_row), "br_out[{0}]".format(i/self.words_per_row),
"wen", "vdd", "gnd"]) "en", "vdd", "gnd"])
def add_layout_pins(self): def add_layout_pins(self):
@ -90,7 +85,7 @@ class write_driver_array(design.design):
height=br_pin.height()) height=br_pin.height())
self.add_layout_pin(text="wen", self.add_layout_pin(text="en",
layer="metal1", layer="metal1",
offset=self.driver_insts[0].get_pin("en").ll().scale(0,1), offset=self.driver_insts[0].get_pin("en").ll().scale(0,1),
width=self.width, width=self.width,