mirror of https://github.com/VLSIDA/OpenRAM.git
Functional tests working with new RBL.
This commit is contained in:
parent
0b13225913
commit
043018e8ba
|
|
@ -72,6 +72,11 @@ class bitcell(design.design):
|
||||||
debug.check(port==0,"One port for bitcell only.")
|
debug.check(port==0,"One port for bitcell only.")
|
||||||
return "br"
|
return "br"
|
||||||
|
|
||||||
|
def get_wl_name(self, port=0):
|
||||||
|
"""Get wl name"""
|
||||||
|
debug.check(port==0,"One port for bitcell only.")
|
||||||
|
return "wl"
|
||||||
|
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Bitcell power in nW. Only characterizes leakage."""
|
"""Bitcell power in nW. Only characterizes leakage."""
|
||||||
from tech import spice
|
from tech import spice
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,11 @@ class bitcell_1rw_1r(design.design):
|
||||||
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
|
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
|
||||||
return "br{}".format(port)
|
return "br{}".format(port)
|
||||||
|
|
||||||
|
def get_wl_name(self, port=0):
|
||||||
|
"""Get wl name by port"""
|
||||||
|
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
|
||||||
|
return "wl{}".format(port)
|
||||||
|
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Bitcell power in nW. Only characterizes leakage."""
|
"""Bitcell power in nW. Only characterizes leakage."""
|
||||||
from tech import spice
|
from tech import spice
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,11 @@ class bitcell_1w_1r(design.design):
|
||||||
"""Get bl name by port"""
|
"""Get bl name by port"""
|
||||||
return "br{}".format(port)
|
return "br{}".format(port)
|
||||||
|
|
||||||
|
def get_wl_name(self, port=0):
|
||||||
|
"""Get wl name by port"""
|
||||||
|
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
|
||||||
|
return "wl{}".format(port)
|
||||||
|
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Bitcell power in nW. Only characterizes leakage."""
|
"""Bitcell power in nW. Only characterizes leakage."""
|
||||||
from tech import spice
|
from tech import spice
|
||||||
|
|
|
||||||
|
|
@ -904,6 +904,12 @@ class pbitcell(design.design):
|
||||||
"""Get bl name by port"""
|
"""Get bl name by port"""
|
||||||
return "br{}".format(port)
|
return "br{}".format(port)
|
||||||
|
|
||||||
|
def get_wl_name(self, port=0):
|
||||||
|
"""Get wl name by port"""
|
||||||
|
debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
|
||||||
|
return "wl{}".format(port)
|
||||||
|
|
||||||
|
|
||||||
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
|
def analytical_delay(self, corner, slew, load=0, swing = 0.5):
|
||||||
parasitic_delay = 1
|
parasitic_delay = 1
|
||||||
size = 0.5 #This accounts for bitline being drained thought the access TX and internal node
|
size = 0.5 #This accounts for bitline being drained thought the access TX and internal node
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,9 @@ class bank(design.design):
|
||||||
for port in self.read_ports:
|
for port in self.read_ports:
|
||||||
for bit in range(self.word_size):
|
for bit in range(self.word_size):
|
||||||
self.add_pin("dout{0}_{1}".format(port,bit),"OUT")
|
self.add_pin("dout{0}_{1}".format(port,bit),"OUT")
|
||||||
|
self.add_pin("rbl_bl{0}_{0}".format(port),"OUT")
|
||||||
|
for port in self.read_ports:
|
||||||
|
self.add_pin("rbl_wl{0}_{0}".format(port),"IN")
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
for bit in range(self.word_size):
|
for bit in range(self.word_size):
|
||||||
self.add_pin("din{0}_{1}".format(port,bit),"IN")
|
self.add_pin("din{0}_{1}".format(port,bit),"IN")
|
||||||
|
|
@ -108,6 +111,7 @@ class bank(design.design):
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.route_bitlines(port)
|
self.route_bitlines(port)
|
||||||
|
self.route_rbl(port)
|
||||||
self.route_port_address(port)
|
self.route_port_address(port)
|
||||||
self.route_column_address_lines(port)
|
self.route_column_address_lines(port)
|
||||||
self.route_control_lines(port)
|
self.route_control_lines(port)
|
||||||
|
|
@ -116,6 +120,20 @@ class bank(design.design):
|
||||||
|
|
||||||
self.route_supplies()
|
self.route_supplies()
|
||||||
|
|
||||||
|
def route_rbl(self,port):
|
||||||
|
""" Route the rbl_bl and rbl_wl """
|
||||||
|
|
||||||
|
if self.port_data[port].has_rbl():
|
||||||
|
bl_name = self.bitcell.get_bl_name(port)
|
||||||
|
bl_pin = self.bitcell_array_inst.get_pin("rbl_{0}_{1}".format(bl_name,port))
|
||||||
|
self.add_layout_pin(text="rbl_bl{0}".format(port),
|
||||||
|
layer=bl_pin.layer,
|
||||||
|
offset=bl_pin.ll(),
|
||||||
|
height=bl_pin.height(),
|
||||||
|
width=bl_pin.width())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def route_bitlines(self, port):
|
def route_bitlines(self, port):
|
||||||
""" Route the bitlines depending on the port type rw, w, or r. """
|
""" Route the bitlines depending on the port type rw, w, or r. """
|
||||||
|
|
||||||
|
|
@ -281,13 +299,13 @@ class bank(design.design):
|
||||||
self.input_control_signals = []
|
self.input_control_signals = []
|
||||||
port_num = 0
|
port_num = 0
|
||||||
for port in range(OPTS.num_rw_ports):
|
for port in range(OPTS.num_rw_ports):
|
||||||
self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num)])
|
self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num), "rbl_wl{}".format(port_num)])
|
||||||
port_num += 1
|
port_num += 1
|
||||||
for port in range(OPTS.num_w_ports):
|
for port in range(OPTS.num_w_ports):
|
||||||
self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num)])
|
self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num)])
|
||||||
port_num += 1
|
port_num += 1
|
||||||
for port in range(OPTS.num_r_ports):
|
for port in range(OPTS.num_r_ports):
|
||||||
self.input_control_signals.append(["wl_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num)])
|
self.input_control_signals.append(["wl_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num), "rbl_wl{}".format(port_num)])
|
||||||
port_num += 1
|
port_num += 1
|
||||||
|
|
||||||
# Number of control lines in the bus for each port
|
# Number of control lines in the bus for each port
|
||||||
|
|
@ -905,6 +923,9 @@ class bank(design.design):
|
||||||
if port in self.read_ports:
|
if port in self.read_ports:
|
||||||
connection.append((self.prefix+"p_en_bar{}".format(port), self.port_data_inst[port].get_pin("p_en_bar").lc()))
|
connection.append((self.prefix+"p_en_bar{}".format(port), self.port_data_inst[port].get_pin("p_en_bar").lc()))
|
||||||
|
|
||||||
|
if port in self.read_ports:
|
||||||
|
connection.append((self.prefix+"rbl_wl{}".format(port), self.bitcell_array_inst.get_pin("rbl_{0}_{1}".format(self.bitcell.get_wl_name(port),port)).lc()))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
|
connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class control_logic(design.design):
|
||||||
self.num_cols = word_size*words_per_row
|
self.num_cols = word_size*words_per_row
|
||||||
self.num_words = num_rows*words_per_row
|
self.num_words = num_rows*words_per_row
|
||||||
|
|
||||||
self.enable_delay_chain_resizing = True
|
self.enable_delay_chain_resizing = False
|
||||||
self.inv_parasitic_delay = logical_effort.logical_effort.pinv
|
self.inv_parasitic_delay = logical_effort.logical_effort.pinv
|
||||||
|
|
||||||
#Determines how much larger the sen delay should be. Accounts for possible error in model.
|
#Determines how much larger the sen delay should be. Accounts for possible error in model.
|
||||||
|
|
@ -73,10 +73,8 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Add the pins to the control logic module. """
|
""" Add the pins to the control logic module. """
|
||||||
for pin in self.input_list + ["clk"]:
|
self.add_pin_list(self.input_list + ["clk"] + self.rbl_list, "INPUT")
|
||||||
self.add_pin(pin,"INPUT")
|
self.add_pin_list(self.output_list,"OUTPUT")
|
||||||
for pin in self.output_list:
|
|
||||||
self.add_pin(pin,"OUTPUT")
|
|
||||||
self.add_pin("vdd","POWER")
|
self.add_pin("vdd","POWER")
|
||||||
self.add_pin("gnd","GROUND")
|
self.add_pin("gnd","GROUND")
|
||||||
|
|
||||||
|
|
@ -139,46 +137,48 @@ class control_logic(design.design):
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.p_en_bar_driver)
|
self.add_mod(self.p_en_bar_driver)
|
||||||
|
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
# if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
from importlib import reload
|
# from importlib import reload
|
||||||
self.delay_chain_resized = False
|
# self.delay_chain_resized = False
|
||||||
c = reload(__import__(OPTS.replica_bitline))
|
# c = reload(__import__(OPTS.replica_bitline))
|
||||||
replica_bitline = getattr(c, OPTS.replica_bitline)
|
# replica_bitline = getattr(c, OPTS.replica_bitline)
|
||||||
bitcell_loads = int(math.ceil(self.num_rows * OPTS.rbl_delay_percentage))
|
# bitcell_loads = int(math.ceil(self.num_rows * OPTS.rbl_delay_percentage))
|
||||||
#Use a model to determine the delays with that heuristic
|
# #Use a model to determine the delays with that heuristic
|
||||||
if OPTS.use_tech_delay_chain_size: #Use tech parameters if set.
|
# if OPTS.use_tech_delay_chain_size: #Use tech parameters if set.
|
||||||
fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage]
|
# fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage]
|
||||||
debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list))
|
# debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list))
|
||||||
self.replica_bitline = factory.create(module_type="replica_bitline",
|
# self.replica_bitline = factory.create(module_type="replica_bitline",
|
||||||
delay_fanout_list=fanout_list,
|
# delay_fanout_list=fanout_list,
|
||||||
bitcell_loads=bitcell_loads)
|
# bitcell_loads=bitcell_loads)
|
||||||
if self.sram != None: #Calculate model value even for specified sizes
|
# if self.sram != None: #Calculate model value even for specified sizes
|
||||||
self.set_sen_wl_delays()
|
# self.set_sen_wl_delays()
|
||||||
|
|
||||||
else: #Otherwise, use a heuristic and/or model based sizing.
|
# else: #Otherwise, use a heuristic and/or model based sizing.
|
||||||
#First use a heuristic
|
# #First use a heuristic
|
||||||
delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
|
# delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
|
||||||
self.replica_bitline = factory.create(module_type="replica_bitline",
|
# self.replica_bitline = factory.create(module_type="replica_bitline",
|
||||||
delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic,
|
# delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic,
|
||||||
bitcell_loads=bitcell_loads)
|
# bitcell_loads=bitcell_loads)
|
||||||
#Resize if necessary, condition depends on resizing method
|
# #Resize if necessary, condition depends on resizing method
|
||||||
if self.sram != None and self.enable_delay_chain_resizing and not self.does_sen_rise_fall_timing_match():
|
# if self.sram != None and self.enable_delay_chain_resizing and not self.does_sen_rise_fall_timing_match():
|
||||||
#This resizes to match fall and rise delays, can make the delay chain weird sizes.
|
# #This resizes to match fall and rise delays, can make the delay chain weird sizes.
|
||||||
stage_list = self.get_dynamic_delay_fanout_list(delay_stages_heuristic, delay_fanout_heuristic)
|
# stage_list = self.get_dynamic_delay_fanout_list(delay_stages_heuristic, delay_fanout_heuristic)
|
||||||
self.replica_bitline = factory.create(module_type="replica_bitline",
|
# self.replica_bitline = factory.create(module_type="replica_bitline",
|
||||||
delay_fanout_list=stage_list,
|
# delay_fanout_list=stage_list,
|
||||||
bitcell_loads=bitcell_loads)
|
# bitcell_loads=bitcell_loads)
|
||||||
|
|
||||||
#This resizes based on total delay.
|
# #This resizes based on total delay.
|
||||||
# delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic)
|
# # delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic)
|
||||||
# self.replica_bitline = factory.create(module_type="replica_bitline",
|
# # self.replica_bitline = factory.create(module_type="replica_bitline",
|
||||||
# delay_fanout_list=[delay_fanout]*delay_stages,
|
# # delay_fanout_list=[delay_fanout]*delay_stages,
|
||||||
# bitcell_loads=bitcell_loads)
|
# # bitcell_loads=bitcell_loads)
|
||||||
|
|
||||||
self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
|
# self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
|
||||||
self.delay_chain_resized = True
|
# self.delay_chain_resized = True
|
||||||
|
|
||||||
self.add_mod(self.replica_bitline)
|
self.delay_chain=factory.create(module_type="delay_chain",
|
||||||
|
fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage])
|
||||||
|
self.add_mod(self.delay_chain)
|
||||||
|
|
||||||
def get_heuristic_delay_chain_size(self):
|
def get_heuristic_delay_chain_size(self):
|
||||||
"""Use a basic heuristic to determine the size of the delay chain used for the Sense Amp Enable """
|
"""Use a basic heuristic to determine the size of the delay chain used for the Sense Amp Enable """
|
||||||
|
|
@ -312,8 +312,13 @@ class control_logic(design.design):
|
||||||
# List of input control signals
|
# List of input control signals
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
self.input_list = ["csb", "web"]
|
self.input_list = ["csb", "web"]
|
||||||
|
self.rbl_list = ["rbl_bl"]
|
||||||
|
elif self.port_type == "r":
|
||||||
|
self.input_list = ["csb"]
|
||||||
|
self.rbl_list = ["rbl_bl"]
|
||||||
else:
|
else:
|
||||||
self.input_list = ["csb"]
|
self.input_list = ["csb"]
|
||||||
|
self.rbl_list = []
|
||||||
|
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
|
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
|
||||||
|
|
@ -332,9 +337,9 @@ class control_logic(design.design):
|
||||||
|
|
||||||
# Outputs to the bank
|
# Outputs to the bank
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
self.output_list = ["s_en", "w_en", "p_en_bar"]
|
self.output_list = ["rbl_wl", "s_en", "w_en", "p_en_bar"]
|
||||||
elif self.port_type == "r":
|
elif self.port_type == "r":
|
||||||
self.output_list = ["s_en", "p_en_bar"]
|
self.output_list = ["rbl_wl", "s_en", "p_en_bar"]
|
||||||
else:
|
else:
|
||||||
self.output_list = ["w_en"]
|
self.output_list = ["w_en"]
|
||||||
self.output_list.append("wl_en")
|
self.output_list.append("wl_en")
|
||||||
|
|
@ -361,11 +366,11 @@ class control_logic(design.design):
|
||||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||||
self.create_wen_row()
|
self.create_wen_row()
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
self.create_rbl_in_row()
|
self.create_rbl_row()
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
self.create_pen_row()
|
self.create_pen_row()
|
||||||
self.create_sen_row()
|
self.create_sen_row()
|
||||||
self.create_rbl()
|
self.create_delay()
|
||||||
|
|
||||||
|
|
||||||
def place_instances(self):
|
def place_instances(self):
|
||||||
|
|
@ -395,17 +400,16 @@ class control_logic(design.design):
|
||||||
height = self.w_en_inst.uy()
|
height = self.w_en_inst.uy()
|
||||||
control_center_y = self.w_en_inst.uy()
|
control_center_y = self.w_en_inst.uy()
|
||||||
row += 1
|
row += 1
|
||||||
if self.port_type == "rw":
|
|
||||||
self.place_rbl_in_row(row)
|
|
||||||
row += 1
|
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
|
self.place_rbl_row(row)
|
||||||
|
row += 1
|
||||||
self.place_pen_row(row)
|
self.place_pen_row(row)
|
||||||
row += 1
|
row += 1
|
||||||
self.place_sen_row(row)
|
self.place_sen_row(row)
|
||||||
row += 1
|
row += 1
|
||||||
self.place_rbl(row)
|
self.place_delay(row)
|
||||||
height = self.rbl_inst.uy()
|
height = self.delay_inst.uy()
|
||||||
control_center_y = self.rbl_inst.by()
|
control_center_y = self.delay_inst.by()
|
||||||
|
|
||||||
# This offset is used for placement of the control logic in the SRAM level.
|
# This offset is used for placement of the control logic in the SRAM level.
|
||||||
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y)
|
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y)
|
||||||
|
|
@ -415,7 +419,7 @@ class control_logic(design.design):
|
||||||
# Max of modules or logic rows
|
# Max of modules or logic rows
|
||||||
self.width = max([inst.rx() for inst in self.row_end_inst])
|
self.width = max([inst.rx() for inst in self.row_end_inst])
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
self.width = max(self.rbl_inst.rx() , self.width)
|
self.width = max(self.delay_inst.rx() , self.width)
|
||||||
self.width += self.m2_pitch
|
self.width += self.m2_pitch
|
||||||
|
|
||||||
def route_all(self):
|
def route_all(self):
|
||||||
|
|
@ -426,7 +430,7 @@ class control_logic(design.design):
|
||||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||||
self.route_wen()
|
self.route_wen()
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
self.route_rbl_in()
|
self.route_rbl()
|
||||||
self.route_pen()
|
self.route_pen()
|
||||||
self.route_sen()
|
self.route_sen()
|
||||||
self.route_clk_buf()
|
self.route_clk_buf()
|
||||||
|
|
@ -435,24 +439,20 @@ class control_logic(design.design):
|
||||||
self.route_supply()
|
self.route_supply()
|
||||||
|
|
||||||
|
|
||||||
def create_rbl(self):
|
def create_delay(self):
|
||||||
""" Create the replica bitline """
|
""" Create the replica bitline """
|
||||||
if self.port_type == "r":
|
self.delay_inst=self.add_inst(name="delay_chain",
|
||||||
input_name = "gated_clk_bar"
|
mod=self.delay_chain)
|
||||||
else:
|
self.connect_inst(["rbl_bl", "pre_s_en", "vdd", "gnd"])
|
||||||
input_name = "rbl_in"
|
|
||||||
self.rbl_inst=self.add_inst(name="replica_bitline",
|
|
||||||
mod=self.replica_bitline)
|
|
||||||
self.connect_inst([input_name, "pre_s_en", "vdd", "gnd"])
|
|
||||||
|
|
||||||
def place_rbl(self,row):
|
def place_delay(self,row):
|
||||||
""" Place the replica bitline """
|
""" Place the replica bitline """
|
||||||
y_off = row * self.and2.height + 2*self.m1_pitch
|
y_off = row * self.and2.height + 2*self.m1_pitch
|
||||||
|
|
||||||
# Add the RBL above the rows
|
# Add the RBL above the rows
|
||||||
# Add to the right of the control rows and routing channel
|
# Add to the right of the control rows and routing channel
|
||||||
offset = vector(0, y_off)
|
offset = vector(0, y_off)
|
||||||
self.rbl_inst.place(offset)
|
self.delay_inst.place(offset)
|
||||||
|
|
||||||
|
|
||||||
def create_clk_buf_row(self):
|
def create_clk_buf_row(self):
|
||||||
|
|
@ -588,44 +588,41 @@ class control_logic(design.design):
|
||||||
self.connect_vertical_bus(wlen_map, self.wl_en_inst, self.rail_offsets)
|
self.connect_vertical_bus(wlen_map, self.wl_en_inst, self.rail_offsets)
|
||||||
self.connect_output(self.wl_en_inst, "Z", "wl_en")
|
self.connect_output(self.wl_en_inst, "Z", "wl_en")
|
||||||
|
|
||||||
def create_rbl_in_row(self):
|
def create_rbl_row(self):
|
||||||
|
|
||||||
# input: gated_clk_bar, we_bar, output: rbl_in
|
# input: gated_clk_bar, we_bar, output: rbl_in
|
||||||
self.rbl_in_inst=self.add_inst(name="and2_rbl_in",
|
self.rbl_inst=self.add_inst(name="and2_rbl",
|
||||||
mod=self.and2)
|
mod=self.and2)
|
||||||
self.connect_inst(["gated_clk_bar", "we_bar", "rbl_in", "vdd", "gnd"])
|
self.connect_inst(["gated_clk_bar", "we_bar", "rbl_wl", "vdd", "gnd"])
|
||||||
|
|
||||||
def place_rbl_in_row(self,row):
|
def place_rbl_row(self,row):
|
||||||
x_off = self.control_x_offset
|
x_off = self.control_x_offset
|
||||||
(y_off,mirror)=self.get_offset(row)
|
(y_off,mirror)=self.get_offset(row)
|
||||||
|
|
||||||
offset = vector(x_off, y_off)
|
offset = vector(x_off, y_off)
|
||||||
self.rbl_in_inst.place(offset, mirror)
|
self.rbl_inst.place(offset, mirror)
|
||||||
|
|
||||||
self.row_end_inst.append(self.rbl_in_inst)
|
self.row_end_inst.append(self.rbl_inst)
|
||||||
|
|
||||||
def route_rbl_in(self):
|
def route_rbl(self):
|
||||||
""" Connect the logic for the rbl_in generation """
|
""" Connect the logic for the rbl_in generation """
|
||||||
|
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
input_name = "we_bar"
|
input_name = "we_bar"
|
||||||
# Connect the NAND gate inputs to the bus
|
# Connect the NAND gate inputs to the bus
|
||||||
rbl_in_map = zip(["A", "B"], ["gated_clk_bar", "we_bar"])
|
rbl_in_map = zip(["A", "B"], ["gated_clk_bar", "we_bar"])
|
||||||
self.connect_vertical_bus(rbl_in_map, self.rbl_in_inst, self.rail_offsets)
|
self.connect_vertical_bus(rbl_in_map, self.rbl_inst, self.rail_offsets)
|
||||||
|
|
||||||
|
|
||||||
# Connect the output of the precharge enable to the RBL input
|
# Connect the output of the precharge enable to the RBL input
|
||||||
if self.port_type == "rw":
|
#if self.port_type == "rw":
|
||||||
out_pos = self.rbl_in_inst.get_pin("Z").center()
|
# out_pos = self.rbl_in_inst.get_pin("Z").center()
|
||||||
else:
|
#else:
|
||||||
out_pos = vector(self.rail_offsets["gated_clk_bar"].x, self.rbl_inst.by()-3*self.m2_pitch)
|
# out_pos = vector(self.rail_offsets["gated_clk_bar"].x, self.rbl_inst.by()-3*self.m2_pitch)
|
||||||
in_pos = self.rbl_inst.get_pin("en").center()
|
|
||||||
mid1 = vector(in_pos.x,out_pos.y)
|
self.copy_layout_pin(self.rbl_inst, "Z", "rbl_wl")
|
||||||
self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, in_pos])
|
|
||||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
|
||||||
offset=out_pos)
|
|
||||||
self.add_via_center(layers=("metal2","via2","metal3"),
|
|
||||||
offset=out_pos)
|
|
||||||
|
|
||||||
def create_pen_row(self):
|
def create_pen_row(self):
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
|
|
@ -698,7 +695,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def route_sen(self):
|
def route_sen(self):
|
||||||
|
|
||||||
out_pos = self.rbl_inst.get_pin("out").bc()
|
out_pos = self.delay_inst.get_pin("out").bc()
|
||||||
in_pos = self.s_en_inst.get_pin("A").lc()
|
in_pos = self.s_en_inst.get_pin("A").lc()
|
||||||
mid1 = vector(out_pos.x,in_pos.y)
|
mid1 = vector(out_pos.x,in_pos.y)
|
||||||
self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos])
|
self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos])
|
||||||
|
|
@ -817,8 +814,8 @@ class control_logic(design.design):
|
||||||
self.add_path("metal1", [row_loc, pin_loc])
|
self.add_path("metal1", [row_loc, pin_loc])
|
||||||
|
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
self.copy_layout_pin(self.rbl_inst,"gnd")
|
self.copy_layout_pin(self.delay_inst,"gnd")
|
||||||
self.copy_layout_pin(self.rbl_inst,"vdd")
|
self.copy_layout_pin(self.delay_inst,"vdd")
|
||||||
|
|
||||||
self.copy_layout_pin(self.ctrl_dff_inst,"gnd")
|
self.copy_layout_pin(self.ctrl_dff_inst,"gnd")
|
||||||
self.copy_layout_pin(self.ctrl_dff_inst,"vdd")
|
self.copy_layout_pin(self.ctrl_dff_inst,"vdd")
|
||||||
|
|
@ -844,7 +841,7 @@ class control_logic(design.design):
|
||||||
# height=pin.height(),
|
# height=pin.height(),
|
||||||
# width=pin.width())
|
# width=pin.width())
|
||||||
|
|
||||||
pin=self.rbl_inst.get_pin("out")
|
pin=self.delay_inst.get_pin("out")
|
||||||
self.add_label_pin(text="out",
|
self.add_label_pin(text="out",
|
||||||
layer=pin.layer,
|
layer=pin.layer,
|
||||||
offset=pin.ll(),
|
offset=pin.ll(),
|
||||||
|
|
|
||||||
|
|
@ -427,3 +427,8 @@ class replica_bitcell_array(design.design):
|
||||||
bitcell_wl_cin = self.cell.get_wl_cin()
|
bitcell_wl_cin = self.cell.get_wl_cin()
|
||||||
total_cin = bitcell_wl_cin * self.column_size
|
total_cin = bitcell_wl_cin * self.column_size
|
||||||
return total_cin
|
return total_cin
|
||||||
|
|
||||||
|
def graph_exclude_bits(self, targ_row, targ_col):
|
||||||
|
"""Excludes bits in column from being added to graph except target"""
|
||||||
|
self.bitcell_array.graph_exclude_bits(targ_row, targ_col)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,11 @@ class options(optparse.Values):
|
||||||
###################
|
###################
|
||||||
# Optimization options
|
# Optimization options
|
||||||
###################
|
###################
|
||||||
rbl_delay_percentage = .5 #Approximate percentage of delay compared to bitlines
|
rbl_delay_percentage = 0.5 #Approximate percentage of delay compared to bitlines
|
||||||
|
|
||||||
# Allow manual adjustment of the delay chain over automatic
|
# Allow manual adjustment of the delay chain over automatic
|
||||||
use_tech_delay_chain_size = False
|
use_tech_delay_chain_size = False
|
||||||
delay_chain_stages = 4
|
delay_chain_stages = 5
|
||||||
delay_chain_fanout_per_stage = 3
|
delay_chain_fanout_per_stage = 3
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,8 @@ class sram_1bank(sram_base):
|
||||||
# The clock gets routed separately and is not a part of the bank
|
# The clock gets routed separately and is not a part of the bank
|
||||||
if "clk" in signal:
|
if "clk" in signal:
|
||||||
continue
|
continue
|
||||||
|
if signal.startswith("rbl"):
|
||||||
|
continue
|
||||||
src_pin = self.control_logic_insts[port].get_pin(signal)
|
src_pin = self.control_logic_insts[port].get_pin(signal)
|
||||||
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
|
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
|
||||||
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
|
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
|
||||||
|
|
|
||||||
|
|
@ -283,8 +283,7 @@ class sram_base(design, verilog, lef):
|
||||||
# Create the bank module (up to four are instantiated)
|
# Create the bank module (up to four are instantiated)
|
||||||
from bank import bank
|
from bank import bank
|
||||||
self.bank = bank(self.sram_config,
|
self.bank = bank(self.sram_config,
|
||||||
name="bank",
|
name="bank")
|
||||||
num_ports=len(self.all_ports))
|
|
||||||
self.add_mod(self.bank)
|
self.add_mod(self.bank)
|
||||||
|
|
||||||
# Create bank decoder
|
# Create bank decoder
|
||||||
|
|
@ -331,6 +330,10 @@ class sram_base(design, verilog, lef):
|
||||||
for port in self.read_ports:
|
for port in self.read_ports:
|
||||||
for bit in range(self.word_size):
|
for bit in range(self.word_size):
|
||||||
temp.append("DOUT{0}[{1}]".format(port,bit))
|
temp.append("DOUT{0}[{1}]".format(port,bit))
|
||||||
|
for port in self.read_ports:
|
||||||
|
temp.append("rbl_bl{0}".format(port))
|
||||||
|
for port in self.read_ports:
|
||||||
|
temp.append("rbl_wl{0}".format(port))
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
for bit in range(self.word_size):
|
for bit in range(self.word_size):
|
||||||
temp.append("BANK_DIN{0}[{1}]".format(port,bit))
|
temp.append("BANK_DIN{0}[{1}]".format(port,bit))
|
||||||
|
|
@ -465,8 +468,12 @@ class sram_base(design, verilog, lef):
|
||||||
if port in self.readwrite_ports:
|
if port in self.readwrite_ports:
|
||||||
temp.append("web{}".format(port))
|
temp.append("web{}".format(port))
|
||||||
temp.append("clk{}".format(port))
|
temp.append("clk{}".format(port))
|
||||||
|
if port in self.read_ports:
|
||||||
|
temp.append("rbl_bl{}".format(port))
|
||||||
|
|
||||||
# Ouputs
|
# Ouputs
|
||||||
|
if port in self.read_ports:
|
||||||
|
temp.append("rbl_wl{}".format(port))
|
||||||
if port in self.read_ports:
|
if port in self.read_ports:
|
||||||
temp.append("s_en{}".format(port))
|
temp.append("s_en{}".format(port))
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,6 @@ class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
d = delay(s.s, tempspice, corner)
|
|
||||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
|
||||||
|
|
||||||
f.num_cycles = 10
|
f.num_cycles = 10
|
||||||
(fail, error) = f.run()
|
(fail, error) = f.run()
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,6 @@ class psram_1bank_4mux_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
d = delay(s.s, tempspice, corner)
|
|
||||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
|
||||||
|
|
||||||
f.num_cycles = 10
|
f.num_cycles = 10
|
||||||
(fail, error) = f.run()
|
(fail, error) = f.run()
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,6 @@ class psram_1bank_8mux_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
d = delay(s.s, tempspice, corner)
|
|
||||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
|
||||||
|
|
||||||
f.num_cycles = 10
|
f.num_cycles = 10
|
||||||
(fail, error) = f.run()
|
(fail, error) = f.run()
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,6 @@ class psram_1bank_nomux_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
d = delay(s.s, tempspice, corner)
|
|
||||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
|
||||||
|
|
||||||
f.num_cycles = 10
|
f.num_cycles = 10
|
||||||
(fail, error) = f.run()
|
(fail, error) = f.run()
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,9 @@ class sram_1bank_2mux_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
d = delay(s.s, tempspice, corner)
|
|
||||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
|
||||||
|
|
||||||
f.num_cycles = 10
|
f.num_cycles = 10
|
||||||
(fail, error) = f.run(feasible_period)
|
(fail, error) = f.run()
|
||||||
self.assertTrue(fail,error)
|
self.assertTrue(fail,error)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,6 @@ class sram_1bank_4mux_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
d = delay(s.s, tempspice, corner)
|
|
||||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
|
||||||
|
|
||||||
f.num_cycles = 10
|
f.num_cycles = 10
|
||||||
(fail, error) = f.run()
|
(fail, error) = f.run()
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,6 @@ class sram_1bank_8mux_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
d = delay(s.s, tempspice, corner)
|
|
||||||
feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
|
|
||||||
|
|
||||||
f.num_cycles = 10
|
f.num_cycles = 10
|
||||||
(fail, error) = f.run()
|
(fail, error) = f.run()
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ class openram_test(unittest.TestCase):
|
||||||
self.fail("LVS mismatch: {}".format(a.name))
|
self.fail("LVS mismatch: {}".format(a.name))
|
||||||
|
|
||||||
# For debug...
|
# For debug...
|
||||||
#import pdb; pdb.set_trace()
|
import pdb; pdb.set_trace()
|
||||||
if OPTS.purge_temp:
|
if OPTS.purge_temp:
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue