mirror of https://github.com/VLSIDA/OpenRAM.git
Fix 1-way single bank LVS bug. Full SRAM still not functional. 8-way has DRC error.
This commit is contained in:
parent
d17711c394
commit
3ea003c367
102
compiler/bank.py
102
compiler/bank.py
|
|
@ -39,13 +39,15 @@ class bank(design.design):
|
|||
self.num_banks = num_banks
|
||||
|
||||
self.compute_sizes()
|
||||
self.add_pins()
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
self.add_modules()
|
||||
|
||||
self.setup_layout_constraints()
|
||||
|
||||
self.route_layout()
|
||||
|
||||
# Can remove the following, but it helps for debug!
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
|
|
@ -56,18 +58,15 @@ class bank(design.design):
|
|||
self.add_pin("ADDR[{0}]".format(i))
|
||||
|
||||
# For more than one bank, we have a bank select and name
|
||||
# the signals gated_*
|
||||
# the signals gated_*.
|
||||
if(self.num_banks > 1):
|
||||
self.add_pin("bank_select")
|
||||
prefix = "gated_"
|
||||
else:
|
||||
prefix = ""
|
||||
self.add_pin(prefix+"s_en")
|
||||
self.add_pin(prefix+"w_en")
|
||||
self.add_pin(prefix+"tri_en_bar")
|
||||
self.add_pin(prefix+"tri_en")
|
||||
self.add_pin(prefix+"clk_bar")
|
||||
self.add_pin(prefix+"clk")
|
||||
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")
|
||||
|
||||
|
|
@ -83,10 +82,10 @@ 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()
|
||||
# Can remove the following, but it helps for debug!
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
#self.offset_all_coordinates()
|
||||
|
||||
|
|
@ -110,7 +109,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()
|
||||
|
||||
|
|
@ -134,7 +132,9 @@ 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_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
|
||||
if self.col_addr_size>0:
|
||||
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
|
||||
|
||||
|
||||
# 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 = []
|
||||
for i in range(self.word_size):
|
||||
temp.append("DATA[{0}]".format(i))
|
||||
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"])
|
||||
|
|
@ -484,10 +473,9 @@ class bank(design.design):
|
|||
NOR+INV gates to gate the control signals in case of multiple
|
||||
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
|
||||
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
|
||||
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):
|
||||
""" Create the address, supply, and control signal central bus lines. """
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
|
|
@ -645,7 +632,7 @@ class bank(design.design):
|
|||
# Control lines (to the right of the GND rail)
|
||||
for i in range(self.num_control_lines):
|
||||
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
|
||||
self.add_rect(layer="metal2",
|
||||
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
|
||||
# pre-decoder and this connection is in metal3
|
||||
connection = []
|
||||
connection.append(("clk_bar", self.msf_data_in_inst.get_pin("clk").lc()))
|
||||
connection.append(("tri_en_bar", self.tri_gate_array_inst.get_pin("en_bar").lc()))
|
||||
connection.append(("tri_en", self.tri_gate_array_inst.get_pin("en").lc()))
|
||||
connection.append(("clk_bar", self.precharge_array_inst.get_pin("clk").lc()))
|
||||
connection.append(("w_en", self.write_driver_array_inst.get_pin("wen").lc()))
|
||||
connection.append(("s_en", self.sense_amp_array_inst.get_pin("sclk").lc()))
|
||||
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()))
|
||||
|
||||
for (control_signal, pin_position) in connection:
|
||||
control_x_offset = self.central_line_xoffset[control_signal] + self.m2_width
|
||||
|
|
@ -1049,7 +1040,7 @@ class bank(design.design):
|
|||
rotate=90)
|
||||
|
||||
# clk to msf address
|
||||
control_signal = "clk"
|
||||
control_signal = 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]
|
||||
|
|
@ -1060,7 +1051,7 @@ class bank(design.design):
|
|||
offset=control_via_position)
|
||||
|
||||
# clk to wordline_driver
|
||||
control_signal = "clk"
|
||||
control_signal = 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]
|
||||
|
|
@ -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
|
||||
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",
|
||||
|
|
@ -1231,6 +1223,7 @@ class bank(design.design):
|
|||
|
||||
# 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
|
||||
|
|
@ -1263,21 +1256,14 @@ class bank(design.design):
|
|||
def add_control_pins(self):
|
||||
""" Add the control signal input pins """
|
||||
|
||||
if self.num_banks==1:
|
||||
# If we are a single bank, just add duplicate pin shapes
|
||||
# on the existing the control bus
|
||||
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)
|
||||
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
|
||||
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)
|
||||
|
||||
|
||||
def connect_rail_from_right(self,inst, pin, rail):
|
||||
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class ms_flop_array(design.design):
|
|||
def add_pins(self):
|
||||
for i in range(self.word_size):
|
||||
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_bar[{0}]".format(i))
|
||||
self.add_pin("clk")
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class precharge_array(design.design):
|
|||
for i in range(self.columns):
|
||||
self.add_pin("bl[{0}]".format(i))
|
||||
self.add_pin("br[{0}]".format(i))
|
||||
self.add_pin("clk")
|
||||
self.add_pin("en")
|
||||
self.add_pin("vdd")
|
||||
|
||||
def create_layout(self):
|
||||
|
|
@ -48,7 +48,7 @@ class precharge_array(design.design):
|
|||
width=self.width,
|
||||
height=drc["minwidth_metal1"])
|
||||
|
||||
self.add_layout_pin(text="clk",
|
||||
self.add_layout_pin(text="en",
|
||||
layer="metal1",
|
||||
offset=self.pc_cell.get_pin("clk").ll(),
|
||||
width=self.width,
|
||||
|
|
@ -77,5 +77,5 @@ class precharge_array(design.design):
|
|||
width=drc["minwidth_metal2"],
|
||||
height=bl_pin.height())
|
||||
self.connect_inst(["bl[{0}]".format(i), "br[{0}]".format(i),
|
||||
"clk", "vdd"])
|
||||
"en", "vdd"])
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class sense_amp_array(design.design):
|
|||
self.add_pin("bl[{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("gnd")
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ class sense_amp_array(design.design):
|
|||
offset=amp_position)
|
||||
self.connect_inst(["bl[{0}]".format(i),"br[{0}]".format(i),
|
||||
"data[{0}]".format(i/self.words_per_row),
|
||||
"sclk", "vdd", "gnd"])
|
||||
"en", "vdd", "gnd"])
|
||||
|
||||
self.add_layout_pin(text="bl[{0}]".format(i),
|
||||
layer="metal2",
|
||||
|
|
@ -111,7 +111,7 @@ class sense_amp_array(design.design):
|
|||
|
||||
# add sclk rail across entire array
|
||||
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",
|
||||
offset=sclk_offset,
|
||||
width=self.width,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
@ -49,16 +49,10 @@ class tri_gate_array(design.design):
|
|||
self.tri_inst = {}
|
||||
for i in range(0,self.columns,self.words_per_row):
|
||||
name = "Xtri_gate{0}".format(i)
|
||||
if (i % 2 == 0 or self.words_per_row > 1):
|
||||
base = vector(i*self.tri.width, 0)
|
||||
mirror = "R0"
|
||||
else:
|
||||
base = vector((i+1)*self.tri.width, 0)
|
||||
mirror = "MY"
|
||||
base = vector(i*self.tri.width, 0)
|
||||
self.tri_inst[i]=self.add_inst(name=name,
|
||||
mod=self.tri,
|
||||
offset=base,
|
||||
mirror=mirror)
|
||||
offset=base)
|
||||
self.connect_inst(["in[{0}]".format(i/self.words_per_row),
|
||||
"out[{0}]".format(i/self.words_per_row),
|
||||
"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):
|
||||
|
||||
# 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")
|
||||
self.add_layout_pin(text="in[{0}]".format(i/self.words_per_row),
|
||||
layer="metal2",
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class write_driver_array(design.design):
|
|||
for i in range(self.word_size):
|
||||
self.add_pin("bl_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("gnd")
|
||||
|
||||
|
|
@ -50,21 +50,16 @@ class write_driver_array(design.design):
|
|||
self.driver_insts = {}
|
||||
for i in range(0,self.columns,self.words_per_row):
|
||||
name = "Xwrite_driver{}".format(i)
|
||||
if (i % 2 == 0 or self.words_per_row>1):
|
||||
base = vector(i * self.driver.width,0)
|
||||
mirror = "R0"
|
||||
else:
|
||||
base = vector((i+1) * self.driver.width,0)
|
||||
mirror = "MY"
|
||||
base = vector(i * self.driver.width,0)
|
||||
|
||||
self.driver_insts[i/self.words_per_row]=self.add_inst(name=name,
|
||||
mod=self.driver,
|
||||
offset=base,
|
||||
mirror=mirror)
|
||||
offset=base)
|
||||
|
||||
self.connect_inst(["data[{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),
|
||||
"wen", "vdd", "gnd"])
|
||||
"en", "vdd", "gnd"])
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
|
@ -90,7 +85,7 @@ class write_driver_array(design.design):
|
|||
height=br_pin.height())
|
||||
|
||||
|
||||
self.add_layout_pin(text="wen",
|
||||
self.add_layout_pin(text="en",
|
||||
layer="metal1",
|
||||
offset=self.driver_insts[0].get_pin("en").ll().scale(0,1),
|
||||
width=self.width,
|
||||
|
|
|
|||
Loading…
Reference in New Issue