mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-09-01 10:39:35 +02:00
Fixed merge conflict.
This commit is contained in:
+26
-88
@@ -82,7 +82,7 @@ class bank(design.design):
|
||||
for port in self.read_ports:
|
||||
for bit in range(self.word_size):
|
||||
self.add_pin("dout{0}_{1}".format(port,bit),"OUTPUT")
|
||||
for port in self.read_ports:
|
||||
for port in self.all_ports:
|
||||
self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUTPUT")
|
||||
for port in self.write_ports:
|
||||
for bit in range(self.word_size):
|
||||
@@ -128,14 +128,13 @@ class bank(design.design):
|
||||
def route_rbl(self,port):
|
||||
""" Route the rbl_bl and rbl_wl """
|
||||
|
||||
if self.port_data[port].has_rbl():
|
||||
bl_pin_name = self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
|
||||
bl_pin = self.bitcell_array_inst.get_pin(bl_pin_name)
|
||||
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())
|
||||
bl_pin_name = self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
|
||||
bl_pin = self.bitcell_array_inst.get_pin(bl_pin_name)
|
||||
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())
|
||||
|
||||
|
||||
|
||||
@@ -202,10 +201,7 @@ class bank(design.design):
|
||||
|
||||
# LOWER RIGHT QUADRANT
|
||||
# Below the bitcell array
|
||||
if self.port_data[port].has_rbl():
|
||||
self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width,0)
|
||||
else:
|
||||
self.port_data_offsets[port] = vector(self.main_bitcell_array_left,0)
|
||||
self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width,0)
|
||||
|
||||
# UPPER LEFT QUADRANT
|
||||
# To the left of the bitcell array
|
||||
@@ -364,36 +360,15 @@ class bank(design.design):
|
||||
self.add_mod(self.port_address)
|
||||
|
||||
|
||||
# The number of replica lines depends on the port configuration
|
||||
rbl_counts = [self.read_ports.count(p) for p in self.all_ports]
|
||||
self.num_rbl = sum(rbl_counts)
|
||||
|
||||
# The replica array indices always start at 0, so this will map them to
|
||||
# the correct SRAM port
|
||||
# (e.g. if port 0 is w, then port 1 will use RBL 0 in replica bitcell array
|
||||
# because write ports don't use an RBL)
|
||||
self.port_rbl_map = {}
|
||||
index = 0
|
||||
for (i,num) in enumerate(rbl_counts):
|
||||
if num>0:
|
||||
self.port_rbl_map[i]=index
|
||||
index += 1
|
||||
if len(rbl_counts)<2:
|
||||
rbl_counts.append(0)
|
||||
|
||||
|
||||
# Which bitcell port should be used in the RBL
|
||||
# For now (since only 2 ports), if port 0 is not a read port, skip it in the RBLs
|
||||
bitcell_ports=list(range(len(self.read_ports)))
|
||||
if 0 not in self.read_ports:
|
||||
bitcell_ports = [x+1 for x in bitcell_ports]
|
||||
self.port_rbl_map = self.all_ports
|
||||
self.num_rbl = len(self.all_ports)
|
||||
|
||||
self.bitcell_array = factory.create(module_type="replica_bitcell_array",
|
||||
cols=self.num_cols,
|
||||
rows=self.num_rows,
|
||||
left_rbl=rbl_counts[0],
|
||||
right_rbl=rbl_counts[1],
|
||||
bitcell_ports=bitcell_ports)
|
||||
left_rbl=1,
|
||||
right_rbl=1 if len(self.all_ports)>1 else 0,
|
||||
bitcell_ports=self.all_ports)
|
||||
self.add_mod(self.bitcell_array)
|
||||
|
||||
|
||||
@@ -421,8 +396,7 @@ class bank(design.design):
|
||||
for wordline in self.wl_names:
|
||||
temp.append("{0}_{1}".format(wordline,row))
|
||||
for port in self.all_ports:
|
||||
if self.port_data[port].has_rbl():
|
||||
temp.append("wl_en{0}".format(port))
|
||||
temp.append("wl_en{0}".format(port))
|
||||
temp.append("vdd")
|
||||
temp.append("gnd")
|
||||
self.connect_inst(temp)
|
||||
@@ -442,11 +416,10 @@ class bank(design.design):
|
||||
mod=self.port_data[port])
|
||||
|
||||
temp = []
|
||||
if self.port_data[port].has_rbl():
|
||||
rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
|
||||
rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port])
|
||||
temp.append(rbl_bl_name)
|
||||
temp.append(rbl_br_name)
|
||||
rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
|
||||
rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port])
|
||||
temp.append(rbl_bl_name)
|
||||
temp.append(rbl_br_name)
|
||||
for col in range(self.num_cols):
|
||||
temp.append("{0}_{1}".format(self.bl_names[port],col))
|
||||
temp.append("{0}_{1}".format(self.br_names[port],col))
|
||||
@@ -710,11 +683,10 @@ class bank(design.design):
|
||||
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
|
||||
|
||||
# Connect the replica bitlines
|
||||
if self.port_data[port].has_rbl():
|
||||
rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
|
||||
rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port])
|
||||
self.connect_bitline(inst1, inst2, rbl_bl_name, "rbl_bl")
|
||||
self.connect_bitline(inst1, inst2, rbl_br_name, "rbl_br")
|
||||
rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
|
||||
rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port])
|
||||
self.connect_bitline(inst1, inst2, rbl_bl_name, "rbl_bl")
|
||||
self.connect_bitline(inst1, inst2, rbl_br_name, "rbl_br")
|
||||
|
||||
|
||||
|
||||
@@ -943,9 +915,8 @@ class bank(design.design):
|
||||
connection = []
|
||||
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:
|
||||
rbl_wl_name = self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port])
|
||||
connection.append((self.prefix+"wl_en{}".format(port), self.bitcell_array_inst.get_pin(rbl_wl_name).lc()))
|
||||
rbl_wl_name = self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port])
|
||||
connection.append((self.prefix+"wl_en{}".format(port), self.bitcell_array_inst.get_pin(rbl_wl_name).lc()))
|
||||
|
||||
if port in self.write_ports:
|
||||
connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
|
||||
@@ -974,40 +945,7 @@ class bank(design.design):
|
||||
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=control_pos)
|
||||
|
||||
def analytical_delay(self, corner, slew, load, port):
|
||||
""" return analytical delay of the bank. This will track the clock to output path"""
|
||||
#FIXME: This delay is determined in the control logic. Should be moved here.
|
||||
# word_driver_delay = self.wordline_driver.analytical_delay(corner,
|
||||
# slew,
|
||||
# self.bitcell_array.input_load())
|
||||
|
||||
#FIXME: Array delay is the same for every port.
|
||||
word_driver_slew = 0
|
||||
if self.words_per_row > 1:
|
||||
bitline_ext_load = self.port_data[port].column_mux_array.get_drain_cin()
|
||||
else:
|
||||
bitline_ext_load = self.port_data[port].sense_amp_array.get_drain_cin()
|
||||
|
||||
bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_slew, bitline_ext_load)
|
||||
|
||||
bitcell_array_slew = 0
|
||||
#This also essentially creates the same delay for each port. Good structure, no substance
|
||||
if self.words_per_row > 1:
|
||||
sa_load = self.port_data[port].sense_amp_array.get_drain_cin()
|
||||
column_mux_delay = self.port_data[port].column_mux_array.analytical_delay(corner,
|
||||
bitcell_array_slew,
|
||||
sa_load)
|
||||
else:
|
||||
column_mux_delay = []
|
||||
|
||||
column_mux_slew = 0
|
||||
sense_amp_delay = self.port_data[port].sense_amp_array.analytical_delay(corner,
|
||||
column_mux_slew,
|
||||
load)
|
||||
# output load of bitcell_array is set to be only small part of bl for sense amp.
|
||||
return bitcell_array_delay + column_mux_delay + sense_amp_delay
|
||||
|
||||
|
||||
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
|
||||
"""Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline"""
|
||||
#Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption
|
||||
|
||||
@@ -148,17 +148,7 @@ class bitcell_array(design.design):
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
for pin in inst.get_pins(pin_name):
|
||||
self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
|
||||
|
||||
def analytical_delay(self, corner, slew, load):
|
||||
"""Returns relative delay of the bitline in the bitcell array"""
|
||||
from tech import parameter
|
||||
#The load being driven/drained is mostly the bitline but could include the sense amp or the column mux.
|
||||
#The load from the bitlines is due to the drain capacitances from all the other bitlines and wire parasitics.
|
||||
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
|
||||
wire_unit_load = .05 * drain_load #Wires add 5% to this.
|
||||
bitline_load = (drain_load+wire_unit_load)*self.row_size
|
||||
return [self.cell.analytical_delay(corner, slew, load+bitline_load)]
|
||||
|
||||
|
||||
def analytical_power(self, corner, load):
|
||||
"""Power of Bitcell array and bitline in nW."""
|
||||
from tech import drc, parameter
|
||||
@@ -197,15 +187,6 @@ class bitcell_array(design.design):
|
||||
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
|
||||
return bl_wire
|
||||
|
||||
def output_load(self, bl_pos=0):
|
||||
bl_wire = self.gen_bl_wire()
|
||||
return bl_wire.wire_c # sense amp only need to charge small portion of the bl
|
||||
# set as one segment for now
|
||||
|
||||
def input_load(self):
|
||||
wl_wire = self.gen_wl_wire()
|
||||
return wl_wire.return_input_cap()
|
||||
|
||||
def get_wordline_cin(self):
|
||||
"""Get the relative input capacitance from the wordline connections in all the bitcell"""
|
||||
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
|
||||
|
||||
@@ -125,33 +125,35 @@ class control_logic(design.design):
|
||||
self.add_mod(self.wl_en_driver)
|
||||
|
||||
# w_en drives every write driver
|
||||
self.wen_and2 = factory.create(module_type="pand2",
|
||||
self.wen_and = factory.create(module_type="pand3",
|
||||
size=self.word_size+8,
|
||||
height=dff_height)
|
||||
self.add_mod(self.wen_and2)
|
||||
self.add_mod(self.wen_and)
|
||||
|
||||
# s_en drives every sense amp
|
||||
self.sen_and2 = factory.create(module_type="pand2",
|
||||
self.sen_and3 = factory.create(module_type="pand3",
|
||||
size=self.word_size,
|
||||
height=dff_height)
|
||||
self.add_mod(self.sen_and2)
|
||||
self.add_mod(self.sen_and3)
|
||||
|
||||
# used to generate inverted signals with low fanout
|
||||
self.inv = factory.create(module_type="pinv",
|
||||
size=1,
|
||||
height=dff_height)
|
||||
self.add_mod(self.inv)
|
||||
|
||||
|
||||
# p_en_bar drives every column in the bitcell array
|
||||
# but it is sized the same as the wl_en driver with
|
||||
# prepended 3 inverter stages to guarantee it is slower and odd polarity
|
||||
self.p_en_bar_driver = factory.create(module_type="pdriver",
|
||||
fanout=self.num_cols,
|
||||
neg_polarity=True,
|
||||
height=dff_height)
|
||||
self.add_mod(self.p_en_bar_driver)
|
||||
|
||||
|
||||
|
||||
self.nand2 = factory.create(module_type="pnand2",
|
||||
height=dff_height)
|
||||
self.add_mod(self.nand2)
|
||||
|
||||
# if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
# from importlib import reload
|
||||
@@ -330,12 +332,9 @@ class control_logic(design.design):
|
||||
if self.port_type == "rw":
|
||||
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:
|
||||
self.input_list = ["csb"]
|
||||
self.rbl_list = []
|
||||
self.rbl_list = ["rbl_bl"]
|
||||
|
||||
if self.port_type == "rw":
|
||||
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
|
||||
@@ -344,11 +343,11 @@ class control_logic(design.design):
|
||||
|
||||
# list of output control signals (for making a vertical bus)
|
||||
if self.port_type == "rw":
|
||||
self.internal_bus_list = ["gated_clk_bar", "gated_clk_buf", "we", "clk_buf", "we_bar", "cs"]
|
||||
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "we", "clk_buf", "we_bar", "cs"]
|
||||
elif self.port_type == "r":
|
||||
self.internal_bus_list = ["gated_clk_bar", "gated_clk_buf", "clk_buf", "cs_bar", "cs"]
|
||||
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs_bar", "cs"]
|
||||
else:
|
||||
self.internal_bus_list = ["gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"]
|
||||
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"]
|
||||
# leave space for the bus plus one extra space
|
||||
self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch
|
||||
|
||||
@@ -382,10 +381,11 @@ class control_logic(design.design):
|
||||
self.create_gated_clk_buf_row()
|
||||
self.create_wlen_row()
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.create_rbl_delay_row()
|
||||
self.create_wen_row()
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.create_sen_row()
|
||||
self.create_delay()
|
||||
self.create_delay()
|
||||
self.create_pen_row()
|
||||
|
||||
|
||||
@@ -419,12 +419,15 @@ class control_logic(design.design):
|
||||
row += 1
|
||||
self.place_pen_row(row)
|
||||
row += 1
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.place_rbl_delay_row(row)
|
||||
row += 1
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.place_sen_row(row)
|
||||
row += 1
|
||||
self.place_delay(row)
|
||||
height = self.delay_inst.uy()
|
||||
control_center_y = self.delay_inst.by()
|
||||
self.place_delay(row)
|
||||
height = self.delay_inst.uy()
|
||||
control_center_y = self.delay_inst.by()
|
||||
|
||||
# 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)
|
||||
@@ -443,9 +446,11 @@ class control_logic(design.design):
|
||||
self.route_dffs()
|
||||
self.route_wlen()
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.route_rbl_delay()
|
||||
self.route_wen()
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.route_sen()
|
||||
self.route_delay()
|
||||
self.route_pen()
|
||||
self.route_clk_buf()
|
||||
self.route_gated_clk_bar()
|
||||
@@ -457,7 +462,7 @@ class control_logic(design.design):
|
||||
""" Create the replica bitline """
|
||||
self.delay_inst=self.add_inst(name="delay_chain",
|
||||
mod=self.delay_chain)
|
||||
self.connect_inst(["rbl_bl", "pre_s_en", "vdd", "gnd"])
|
||||
self.connect_inst(["rbl_bl", "rbl_bl_delay", "vdd", "gnd"])
|
||||
|
||||
def place_delay(self,row):
|
||||
""" Place the replica bitline """
|
||||
@@ -468,6 +473,22 @@ class control_logic(design.design):
|
||||
offset = vector(self.delay_chain.width, y_off)
|
||||
self.delay_inst.place(offset, mirror="MY")
|
||||
|
||||
def route_delay(self):
|
||||
|
||||
out_pos = self.delay_inst.get_pin("out").bc()
|
||||
# Connect to the rail level with the vdd rail
|
||||
# Use pen since it is in every type of control logic
|
||||
vdd_ypos = self.p_en_bar_nand_inst.get_pin("vdd").by()
|
||||
in_pos = vector(self.rail_offsets["rbl_bl_delay"].x,vdd_ypos)
|
||||
mid1 = vector(out_pos.x,in_pos.y)
|
||||
self.add_wire(("metal1","via1","metal2"),[out_pos, mid1, in_pos])
|
||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||
offset=in_pos)
|
||||
|
||||
|
||||
# Input from RBL goes to the delay line for futher delay
|
||||
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
|
||||
|
||||
|
||||
def create_clk_buf_row(self):
|
||||
""" Create the multistage and gated clock buffer """
|
||||
@@ -476,12 +497,9 @@ class control_logic(design.design):
|
||||
self.connect_inst(["clk","clk_buf","vdd","gnd"])
|
||||
|
||||
def place_clk_buf_row(self,row):
|
||||
""" Place the multistage clock buffer below the control flops """
|
||||
x_off = self.control_x_offset
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
offset = vector(x_off,y_off)
|
||||
self.clk_buf_inst.place(offset, mirror)
|
||||
x_offset = self.place_util(self.clk_buf_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.clk_buf_inst)
|
||||
|
||||
@@ -518,17 +536,10 @@ class control_logic(design.design):
|
||||
self.connect_inst(["cs","clk_bar","gated_clk_bar","vdd","gnd"])
|
||||
|
||||
def place_gated_clk_bar_row(self,row):
|
||||
""" Place the gated clk logic below the control flops """
|
||||
x_off = self.control_x_offset
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
offset = vector(x_off,y_off)
|
||||
self.clk_bar_inst.place(offset, mirror)
|
||||
|
||||
x_off += self.inv.width
|
||||
|
||||
offset = vector(x_off,y_off)
|
||||
self.gated_clk_bar_inst.place(offset, mirror)
|
||||
x_offset = self.place_util(self.clk_bar_inst, x_offset, row)
|
||||
x_offset = self.place_util(self.gated_clk_bar_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.gated_clk_bar_inst)
|
||||
|
||||
@@ -562,12 +573,9 @@ class control_logic(design.design):
|
||||
self.connect_inst(["clk_buf", "cs","gated_clk_buf","vdd","gnd"])
|
||||
|
||||
def place_gated_clk_buf_row(self,row):
|
||||
""" Place the gated clk logic below the control flops """
|
||||
x_off = self.control_x_offset
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
|
||||
offset = vector(x_off,y_off)
|
||||
self.gated_clk_buf_inst.place(offset, mirror)
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
x_offset = self.place_util(self.gated_clk_buf_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.gated_clk_buf_inst)
|
||||
|
||||
@@ -589,11 +597,9 @@ class control_logic(design.design):
|
||||
self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"])
|
||||
|
||||
def place_wlen_row(self, row):
|
||||
x_off = self.control_x_offset
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
|
||||
offset = vector(x_off, y_off)
|
||||
self.wl_en_inst.place(offset, mirror)
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
x_offset = self.place_util(self.wl_en_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.wl_en_inst)
|
||||
|
||||
@@ -604,25 +610,32 @@ class control_logic(design.design):
|
||||
self.connect_output(self.wl_en_inst, "Z", "wl_en")
|
||||
|
||||
def create_pen_row(self):
|
||||
# input: gated_clk_bar, output: p_en_bar
|
||||
self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar",
|
||||
mod=self.p_en_bar_driver)
|
||||
self.connect_inst(["gated_clk_buf", "p_en_bar", "vdd", "gnd"])
|
||||
|
||||
self.p_en_bar_nand_inst=self.add_inst(name="nand_p_en_bar",
|
||||
mod=self.nand2)
|
||||
self.connect_inst(["gated_clk_buf", "rbl_bl_delay", "p_en_bar_unbuf", "vdd", "gnd"])
|
||||
|
||||
self.p_en_bar_driver_inst=self.add_inst(name="buf_p_en_bar",
|
||||
mod=self.p_en_bar_driver)
|
||||
self.connect_inst(["p_en_bar_unbuf", "p_en_bar", "vdd", "gnd"])
|
||||
|
||||
def place_pen_row(self,row):
|
||||
x_off = self.control_x_offset
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
offset = vector(x_off,y_off)
|
||||
self.p_en_bar_inst.place(offset, mirror)
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
self.row_end_inst.append(self.p_en_bar_inst)
|
||||
x_offset = self.place_util(self.p_en_bar_nand_inst, x_offset, row)
|
||||
x_offset = self.place_util(self.p_en_bar_driver_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.p_en_bar_driver_inst)
|
||||
|
||||
def route_pen(self):
|
||||
in_map = zip(["A"], ["gated_clk_buf"])
|
||||
self.connect_vertical_bus(in_map, self.p_en_bar_inst, self.rail_offsets)
|
||||
in_map = zip(["A", "B"], ["gated_clk_buf", "rbl_bl_delay"])
|
||||
self.connect_vertical_bus(in_map, self.p_en_bar_nand_inst, self.rail_offsets)
|
||||
|
||||
out_pos = self.p_en_bar_nand_inst.get_pin("Z").rc()
|
||||
in_pos = self.p_en_bar_driver_inst.get_pin("A").lc()
|
||||
mid1 = vector(out_pos.x,in_pos.y)
|
||||
self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos])
|
||||
|
||||
self.connect_output(self.p_en_bar_inst, "Z", "p_en_bar")
|
||||
self.connect_output(self.p_en_bar_driver_inst, "Z", "p_en_bar")
|
||||
|
||||
def create_sen_row(self):
|
||||
""" Create the sense enable buffer. """
|
||||
@@ -632,20 +645,14 @@ class control_logic(design.design):
|
||||
input_name = "cs_bar"
|
||||
# GATE FOR S_EN
|
||||
self.s_en_gate_inst = self.add_inst(name="buf_s_en_and",
|
||||
mod=self.sen_and2)
|
||||
self.connect_inst(["pre_s_en", input_name, "s_en", "vdd", "gnd"])
|
||||
mod=self.sen_and3)
|
||||
self.connect_inst(["rbl_bl_delay", "gated_clk_bar", input_name, "s_en", "vdd", "gnd"])
|
||||
|
||||
|
||||
def place_sen_row(self,row):
|
||||
"""
|
||||
The sense enable buffer gets placed to the far right of the
|
||||
row.
|
||||
"""
|
||||
x_off = self.control_x_offset
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
offset = vector(x_off, y_off)
|
||||
self.s_en_gate_inst.place(offset, mirror)
|
||||
x_offset = self.place_util(self.s_en_gate_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.s_en_gate_inst)
|
||||
|
||||
@@ -657,22 +664,41 @@ class control_logic(design.design):
|
||||
else:
|
||||
input_name = "cs_bar"
|
||||
|
||||
sen_map = zip(["B"], [input_name])
|
||||
sen_map = zip(["A", "B", "C"], ["rbl_bl_delay", "gated_clk_bar", input_name])
|
||||
self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.rail_offsets)
|
||||
|
||||
out_pos = self.delay_inst.get_pin("out").bc()
|
||||
in_pos = self.s_en_gate_inst.get_pin("A").lc()
|
||||
mid1 = vector(out_pos.x,in_pos.y)
|
||||
self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos])
|
||||
|
||||
self.connect_output(self.s_en_gate_inst, "Z", "s_en")
|
||||
|
||||
# Input from RBL goes to the delay line for futher delay
|
||||
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
|
||||
|
||||
|
||||
def create_rbl_delay_row(self):
|
||||
|
||||
self.rbl_bl_delay_inv_inst = self.add_inst(name="rbl_bl_delay_inv",
|
||||
mod=self.inv)
|
||||
self.connect_inst(["rbl_bl_delay", "rbl_bl_delay_bar", "vdd", "gnd"])
|
||||
|
||||
def place_rbl_delay_row(self,row):
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
x_offset = self.place_util(self.rbl_bl_delay_inv_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.rbl_bl_delay_inv_inst)
|
||||
|
||||
def route_rbl_delay(self):
|
||||
# Connect from delay line
|
||||
# Connect to rail
|
||||
|
||||
rbl_map = zip(["Z"], ["rbl_bl_delay_bar"])
|
||||
self.connect_vertical_bus(rbl_map, self.rbl_bl_delay_inv_inst, self.rail_offsets, ("metal3", "via2", "metal2"))
|
||||
# The pin is on M1, so we need another via as well
|
||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||
offset=self.rbl_bl_delay_inv_inst.get_pin("Z").center())
|
||||
|
||||
|
||||
rbl_map = zip(["A"], ["rbl_bl_delay"])
|
||||
self.connect_vertical_bus(rbl_map, self.rbl_bl_delay_inv_inst, self.rail_offsets)
|
||||
|
||||
def create_wen_row(self):
|
||||
|
||||
# input: we (or cs) output: w_en
|
||||
if self.port_type == "rw":
|
||||
input_name = "we"
|
||||
@@ -682,16 +708,14 @@ class control_logic(design.design):
|
||||
|
||||
# GATE THE W_EN
|
||||
self.w_en_gate_inst = self.add_inst(name="w_en_and",
|
||||
mod=self.wen_and2)
|
||||
self.connect_inst([input_name, "gated_clk_bar", "w_en", "vdd", "gnd"])
|
||||
mod=self.wen_and)
|
||||
self.connect_inst([input_name, "rbl_bl_delay_bar", "gated_clk_bar", "w_en", "vdd", "gnd"])
|
||||
|
||||
|
||||
def place_wen_row(self,row):
|
||||
x_off = self.ctrl_dff_inst.width + self.internal_bus_width
|
||||
(y_off,mirror)=self.get_offset(row)
|
||||
|
||||
offset = vector(x_off, y_off)
|
||||
self.w_en_gate_inst.place(offset, mirror)
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
x_offset = self.place_util(self.w_en_gate_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.w_en_gate_inst)
|
||||
|
||||
@@ -702,7 +726,7 @@ class control_logic(design.design):
|
||||
# No we for write-only reports, so use cs
|
||||
input_name = "cs"
|
||||
|
||||
wen_map = zip(["A", "B"], [input_name, "gated_clk_bar"])
|
||||
wen_map = zip(["A", "B", "C"], [input_name, "rbl_bl_delay_bar", "gated_clk_bar"])
|
||||
self.connect_vertical_bus(wen_map, self.w_en_gate_inst, self.rail_offsets)
|
||||
|
||||
self.connect_output(self.w_en_gate_inst, "Z", "w_en")
|
||||
@@ -781,9 +805,8 @@ class control_logic(design.design):
|
||||
self.add_power_pin("gnd", pin_loc)
|
||||
self.add_path("metal1", [row_loc, pin_loc])
|
||||
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.copy_layout_pin(self.delay_inst,"gnd")
|
||||
self.copy_layout_pin(self.delay_inst,"vdd")
|
||||
self.copy_layout_pin(self.delay_inst,"gnd")
|
||||
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,"vdd")
|
||||
@@ -901,7 +924,8 @@ class control_logic(design.design):
|
||||
last_stage_rise = False
|
||||
|
||||
#First stage(s), clk -(pdriver)-> clk_buf.
|
||||
clk_buf_cout = self.replica_bitline.get_en_cin()
|
||||
#clk_buf_cout = self.replica_bitline.get_en_cin()
|
||||
clk_buf_cout = 0
|
||||
stage_effort_list += self.clk_buf_driver.get_stage_efforts(clk_buf_cout, last_stage_rise)
|
||||
last_stage_rise = stage_effort_list[-1].is_rise
|
||||
|
||||
@@ -948,3 +972,11 @@ class control_logic(design.design):
|
||||
self.graph_inst_exclude.add(self.ctrl_dff_inst)
|
||||
if self.port_type=="rw" or self.port_type=="w":
|
||||
self.graph_inst_exclude.add(self.w_en_gate_inst)
|
||||
|
||||
def place_util(self, inst, x_offset, row):
|
||||
""" Utility to place a row and compute the next offset """
|
||||
|
||||
(y_offset,mirror)=self.get_offset(row)
|
||||
offset = vector(x_offset, y_offset)
|
||||
inst.place(offset, mirror)
|
||||
return x_offset+inst.width
|
||||
|
||||
@@ -48,11 +48,6 @@ class dff(design.design):
|
||||
transition_prob = spice["flop_transition_prob"]
|
||||
return transition_prob*(c_load + c_para)
|
||||
|
||||
def analytical_delay(self, corner, slew, load = 0.0):
|
||||
# dont know how to calculate this now, use constant in tech file
|
||||
result = self.return_delay(spice["dff_delay"], spice["dff_slew"])
|
||||
return result
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
|
||||
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
|
||||
|
||||
@@ -160,11 +160,6 @@ class dff_array(design.design):
|
||||
self.add_via_center(layers=("metal2","via2","metal3"),
|
||||
offset=vector(clk_pin.cx(),clk_ypos))
|
||||
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load=0.0):
|
||||
return self.dff.analytical_delay(corner, slew=slew, load=load)
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
||||
dff_clk_cin = self.dff.get_clk_cin()
|
||||
|
||||
@@ -177,16 +177,7 @@ class dff_buf(design.design):
|
||||
self.add_path("metal1", [self.mid_qb_pos, qb_pos])
|
||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||
offset=qb_pos)
|
||||
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load=0.0):
|
||||
""" Calculate the analytical delay of DFF-> INV -> INV """
|
||||
dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load())
|
||||
inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=self.inv2.input_load())
|
||||
inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
|
||||
return dff_delay + inv1_delay + inv2_delay
|
||||
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
|
||||
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
|
||||
|
||||
@@ -193,11 +193,6 @@ class dff_buf_array(design.design):
|
||||
self.add_via_center(layers=("metal2","via2","metal3"),
|
||||
offset=vector(clk_pin.cx(),clk_ypos))
|
||||
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load=0.0):
|
||||
return self.dff.analytical_delay(slew=slew, load=load)
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
||||
dff_clk_cin = self.dff.get_clk_cin()
|
||||
|
||||
@@ -150,15 +150,7 @@ class dff_inv(design.design):
|
||||
offset=dout_pin.center())
|
||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||
offset=dout_pin.center())
|
||||
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load=0.0):
|
||||
""" Calculate the analytical delay of DFF-> INV -> INV """
|
||||
dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load())
|
||||
inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=load)
|
||||
return dff_delay + inv1_delay
|
||||
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
|
||||
return self.dff.get_clk_cin()
|
||||
|
||||
@@ -190,12 +190,6 @@ class dff_inv_array(design.design):
|
||||
self.add_via_center(layers=("metal2","via2","metal3"),
|
||||
offset=vector(clk_pin.cx(),clk_ypos))
|
||||
|
||||
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load=0.0):
|
||||
return self.dff.analytical_delay(corner, slew=slew, load=load)
|
||||
|
||||
def get_clk_cin(self):
|
||||
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
|
||||
dff_clk_cin = self.dff.get_clk_cin()
|
||||
|
||||
@@ -596,28 +596,6 @@ class hierarchical_decoder(design.design):
|
||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||
offset=rail_pos)
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load = 0.0):
|
||||
# A -> out
|
||||
if self.determine_predecodes(self.num_inputs)[1]==0:
|
||||
pre = self.pre2_4
|
||||
nand = self.nand2
|
||||
else:
|
||||
pre = self.pre3_8
|
||||
nand = self.nand3
|
||||
a_t_out_delay = pre.analytical_delay(corner, slew=slew,load = nand.input_load())
|
||||
|
||||
# out -> z
|
||||
out_t_z_delay = nand.analytical_delay(corner, slew= a_t_out_delay.slew,
|
||||
load = self.inv.input_load())
|
||||
result = a_t_out_delay + out_t_z_delay
|
||||
|
||||
# Z -> decode_out
|
||||
z_t_decodeout_delay = self.inv.analytical_delay(corner, slew = out_t_z_delay.slew , load = load)
|
||||
result = result + z_t_decodeout_delay
|
||||
return result
|
||||
|
||||
|
||||
def input_load(self):
|
||||
if self.determine_predecodes(self.num_inputs)[1]==0:
|
||||
pre = self.pre2_4
|
||||
|
||||
@@ -56,21 +56,4 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
||||
["A_0", "Abar_1"],
|
||||
["Abar_0", "A_1"],
|
||||
["A_0", "A_1"]]
|
||||
return combination
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load = 0.0 ):
|
||||
# in -> inbar
|
||||
a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load())
|
||||
|
||||
# inbar -> z
|
||||
b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load())
|
||||
|
||||
# Z -> out
|
||||
a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load)
|
||||
|
||||
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
||||
|
||||
|
||||
def input_load(self):
|
||||
return self.nand.input_load()
|
||||
return combination
|
||||
@@ -65,21 +65,4 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||
["A_0", "Abar_1", "A_2"],
|
||||
["Abar_0", "A_1", "A_2"],
|
||||
["A_0", "A_1", "A_2"]]
|
||||
return combination
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load = 0.0 ):
|
||||
# A -> Abar
|
||||
a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load())
|
||||
|
||||
# Abar -> z
|
||||
b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load())
|
||||
|
||||
# Z -> out
|
||||
a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load)
|
||||
|
||||
return a_t_b_delay + b_t_z_delay + a_t_out_delay
|
||||
|
||||
|
||||
def input_load(self):
|
||||
return self.nand.input_load()
|
||||
return combination
|
||||
@@ -827,22 +827,4 @@ class multibank(design.design):
|
||||
rotate=90)
|
||||
self.add_via(layers=("metal2","via2","metal3"),
|
||||
offset=in_pin + self.m2m3_via_offset,
|
||||
rotate=90)
|
||||
|
||||
def analytical_delay(self, corner, slew, load):
|
||||
""" return analytical delay of the bank"""
|
||||
decoder_delay = self.row_decoder.analytical_delay(corner, slew, self.wordline_driver.input_load())
|
||||
|
||||
word_driver_delay = self.wordline_driver.analytical_delay(corner, decoder_delay.slew, self.bitcell_array.input_load())
|
||||
|
||||
bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_delay.slew)
|
||||
|
||||
bl_t_data_out_delay = self.sense_amp_array.analytical_delay(corner, bitcell_array_delay.slew,
|
||||
self.bitcell_array.output_load())
|
||||
# output load of bitcell_array is set to be only small part of bl for sense amp.
|
||||
|
||||
data_t_DATA_delay = self.tri_gate_array.analytical_delay(corner, bl_t_data_out_delay.slew, load)
|
||||
|
||||
result = decoder_delay + word_driver_delay + bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_delay
|
||||
return result
|
||||
|
||||
rotate=90)
|
||||
@@ -82,9 +82,8 @@ class port_data(design.design):
|
||||
def add_pins(self):
|
||||
""" Adding pins for port address module"""
|
||||
|
||||
if self.has_rbl():
|
||||
self.add_pin("rbl_bl","INOUT")
|
||||
self.add_pin("rbl_br","INOUT")
|
||||
self.add_pin("rbl_bl","INOUT")
|
||||
self.add_pin("rbl_br","INOUT")
|
||||
for bit in range(self.num_cols):
|
||||
self.add_pin("{0}_{1}".format(self.bl_names[self.port], bit),"INOUT")
|
||||
self.add_pin("{0}_{1}".format(self.br_names[self.port], bit),"INOUT")
|
||||
@@ -155,29 +154,20 @@ class port_data(design.design):
|
||||
|
||||
def add_modules(self):
|
||||
|
||||
if self.port in self.read_ports:
|
||||
# Extra column +1 is for RBL
|
||||
# Precharge will be shifted left if needed
|
||||
self.precharge_array = factory.create(module_type="precharge_array",
|
||||
columns=self.num_cols + 1,
|
||||
bitcell_bl=self.bl_names[self.port],
|
||||
bitcell_br=self.br_names[self.port])
|
||||
self.add_mod(self.precharge_array)
|
||||
# Extra column +1 is for RBL
|
||||
# Precharge will be shifted left if needed
|
||||
self.precharge_array = factory.create(module_type="precharge_array",
|
||||
columns=self.num_cols + 1,
|
||||
bitcell_bl=self.bl_names[self.port],
|
||||
bitcell_br=self.br_names[self.port])
|
||||
self.add_mod(self.precharge_array)
|
||||
|
||||
if self.port in self.read_ports:
|
||||
self.sense_amp_array = factory.create(module_type="sense_amp_array",
|
||||
word_size=self.word_size,
|
||||
words_per_row=self.words_per_row)
|
||||
self.add_mod(self.sense_amp_array)
|
||||
else:
|
||||
# Precharge is needed when we have a column mux or for byte writes
|
||||
# to prevent corruption of half-selected cells, so just always add it
|
||||
# This is a little power inefficient for write ports without a column mux,
|
||||
# but it is simpler.
|
||||
self.precharge_array = factory.create(module_type="precharge_array",
|
||||
columns=self.num_cols,
|
||||
bitcell_bl=self.bl_names[self.port],
|
||||
bitcell_br=self.br_names[self.port])
|
||||
self.add_mod(self.precharge_array)
|
||||
self.sense_amp_array = None
|
||||
|
||||
|
||||
@@ -205,7 +195,7 @@ class port_data(design.design):
|
||||
write_size=self.write_size)
|
||||
self.add_mod(self.write_mask_and_array)
|
||||
else:
|
||||
self.write_mask_and_array_inst = None
|
||||
self.write_mask_and_array = None
|
||||
|
||||
else:
|
||||
self.write_driver_array = None
|
||||
@@ -243,14 +233,14 @@ class port_data(design.design):
|
||||
|
||||
temp = []
|
||||
# Use left BLs for RBL
|
||||
if self.has_rbl() and self.port==0:
|
||||
if self.port==0:
|
||||
temp.append("rbl_bl")
|
||||
temp.append("rbl_br")
|
||||
for bit in range(self.num_cols):
|
||||
temp.append(self.bl_names[self.port]+"_{0}".format(bit))
|
||||
temp.append(self.br_names[self.port]+"_{0}".format(bit))
|
||||
# Use right BLs for RBL
|
||||
if self.has_rbl() and self.port==1:
|
||||
if self.port==1:
|
||||
temp.append("rbl_bl")
|
||||
temp.append("rbl_br")
|
||||
temp.extend(["p_en_bar", "vdd"])
|
||||
@@ -379,7 +369,7 @@ class port_data(design.design):
|
||||
vertical_port_order.append(self.write_mask_and_array_inst)
|
||||
|
||||
# Add one column for the the RBL
|
||||
if self.has_rbl() and self.port == 0:
|
||||
if self.port==0:
|
||||
x_offset = self.bitcell.width
|
||||
else:
|
||||
x_offset = 0
|
||||
@@ -478,7 +468,7 @@ class port_data(design.design):
|
||||
|
||||
inst1 = self.column_mux_array_inst
|
||||
inst2 = self.precharge_array_inst
|
||||
if self.has_rbl() and self.port==0:
|
||||
if self.port==0:
|
||||
self.connect_bitlines(inst1, inst2, self.num_cols, inst2_start_bit=1)
|
||||
else:
|
||||
self.connect_bitlines(inst1, inst2, self.num_cols)
|
||||
@@ -499,7 +489,7 @@ class port_data(design.design):
|
||||
inst1 = self.precharge_array_inst
|
||||
inst1_bl_name = "bl_{}"
|
||||
inst1_br_name = "br_{}"
|
||||
if self.has_rbl() and self.port==0:
|
||||
if self.port==0:
|
||||
start_bit=1
|
||||
else:
|
||||
start_bit=0
|
||||
@@ -524,7 +514,7 @@ class port_data(design.design):
|
||||
inst1 = self.precharge_array_inst
|
||||
inst1_bl_name = "bl_{}"
|
||||
inst1_br_name = "br_{}"
|
||||
if self.has_rbl() and self.port==0:
|
||||
if self.port==0:
|
||||
start_bit=1
|
||||
else:
|
||||
start_bit=0
|
||||
@@ -560,11 +550,11 @@ class port_data(design.design):
|
||||
""" Add the bitline pins for the given port """
|
||||
|
||||
# Connect one bitline to the RBL and offset the indices for the other BLs
|
||||
if self.has_rbl() and self.port==0:
|
||||
if self.port==0:
|
||||
self.copy_layout_pin(self.precharge_array_inst, "bl_0", "rbl_bl")
|
||||
self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br")
|
||||
bit_offset=1
|
||||
elif self.has_rbl() and self.port==1:
|
||||
elif self.port==1:
|
||||
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols), "rbl_bl")
|
||||
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols), "rbl_br")
|
||||
bit_offset=0
|
||||
@@ -669,5 +659,3 @@ class port_data(design.design):
|
||||
if self.precharge_array_inst:
|
||||
self.graph_inst_exclude.add(self.precharge_array_inst)
|
||||
|
||||
def has_rbl(self):
|
||||
return self.port in self.read_ports
|
||||
|
||||
@@ -35,7 +35,7 @@ class replica_bitcell_array(design.design):
|
||||
self.right_rbl = right_rbl
|
||||
self.bitcell_ports = bitcell_ports
|
||||
|
||||
debug.check(left_rbl+right_rbl==len(self.read_ports),"Invalid number of RBLs for port configuration.")
|
||||
debug.check(left_rbl+right_rbl==len(self.all_ports),"Invalid number of RBLs for port configuration.")
|
||||
debug.check(left_rbl+right_rbl==len(self.bitcell_ports),"Bitcell ports must match total RBLs.")
|
||||
|
||||
# Two dummy rows/cols plus replica for each port
|
||||
@@ -373,17 +373,7 @@ class replica_bitcell_array(design.design):
|
||||
def get_rbl_br_name(self, port):
|
||||
""" Return the BR for the given RBL port """
|
||||
return self.rbl_br_names[port]
|
||||
|
||||
def analytical_delay(self, corner, slew, load):
|
||||
"""Returns relative delay of the bitline in the bitcell array"""
|
||||
from tech import parameter
|
||||
#The load being driven/drained is mostly the bitline but could include the sense amp or the column mux.
|
||||
#The load from the bitlines is due to the drain capacitances from all the other bitlines and wire parasitics.
|
||||
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
|
||||
wire_unit_load = 0.05 * drain_load #Wires add 5% to this.
|
||||
bitline_load = (drain_load+wire_unit_load)*self.row_size
|
||||
return [self.cell.analytical_delay(corner, slew, load+bitline_load)]
|
||||
|
||||
|
||||
def analytical_power(self, corner, load):
|
||||
"""Power of Bitcell array and bitline in nW."""
|
||||
from tech import drc, parameter
|
||||
@@ -403,15 +393,6 @@ class replica_bitcell_array(design.design):
|
||||
cell_power.leakage * self.column_size * self.row_size)
|
||||
return total_power
|
||||
|
||||
def gen_wl_wire(self):
|
||||
if OPTS.netlist_only:
|
||||
width = 0
|
||||
else:
|
||||
width = self.width
|
||||
wl_wire = self.generate_rc_net(int(self.column_size), width, drc("minwidth_metal1"))
|
||||
wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
|
||||
return wl_wire
|
||||
|
||||
def gen_bl_wire(self):
|
||||
if OPTS.netlist_only:
|
||||
height = 0
|
||||
@@ -422,15 +403,6 @@ class replica_bitcell_array(design.design):
|
||||
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
|
||||
return bl_wire
|
||||
|
||||
def output_load(self, bl_pos=0):
|
||||
bl_wire = self.gen_bl_wire()
|
||||
return bl_wire.wire_c # sense amp only need to charge small portion of the bl
|
||||
# set as one segment for now
|
||||
|
||||
def input_load(self):
|
||||
wl_wire = self.gen_wl_wire()
|
||||
return wl_wire.return_input_cap()
|
||||
|
||||
def get_wordline_cin(self):
|
||||
"""Get the relative input capacitance from the wordline connections in all the bitcell"""
|
||||
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
|
||||
|
||||
@@ -33,15 +33,18 @@ class sense_amp(design.design):
|
||||
self.pin_map = sense_amp.pin_map
|
||||
self.add_pin_types(self.type_list)
|
||||
|
||||
def input_load(self):
|
||||
def get_cin(self):
|
||||
|
||||
# FIXME: This input load will be applied to both the s_en timing and bitline timing.
|
||||
|
||||
#Input load for the bitlines which are connected to the source/drain of a TX. Not the selects.
|
||||
from tech import spice, parameter
|
||||
# Default is 8x. Per Samira and Hodges-Jackson book:
|
||||
# "Column-mux transistors driven by the decoder must be sized for optimal speed"
|
||||
bitline_pmos_size = 8 #FIXME: This should be set somewhere and referenced. Probably in tech file.
|
||||
return spice["min_tx_drain_c"]*(bitline_pmos_size/parameter["min_tx_size"])#ff
|
||||
return spice["min_tx_drain_c"]*(bitline_pmos_size)#ff
|
||||
|
||||
def analytical_delay(self, corner, slew, load):
|
||||
def get_stage_effort(self, load):
|
||||
#Delay of the sense amp will depend on the size of the amp and the output load.
|
||||
parasitic_delay = 1
|
||||
cin = (parameter["sa_inv_pmos_size"] + parameter["sa_inv_nmos_size"])/drc("minwidth_tx")
|
||||
|
||||
@@ -144,10 +144,7 @@ class sense_amp_array(design.design):
|
||||
|
||||
def input_load(self):
|
||||
return self.amp.input_load()
|
||||
|
||||
def analytical_delay(self, corner, slew, load):
|
||||
return [self.amp.analytical_delay(corner, slew=slew, load=load)]
|
||||
|
||||
|
||||
def get_en_cin(self):
|
||||
"""Get the relative capacitance of all the sense amp enable connections in the array"""
|
||||
sense_amp_en_cin = self.amp.get_en_cin()
|
||||
|
||||
@@ -210,15 +210,6 @@ class single_level_column_mux_array(design.design):
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=br_out_offset)
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load):
|
||||
from tech import parameter
|
||||
"""Returns relative delay that the column mux adds"""
|
||||
#Single level column mux will add parasitic loads from other mux pass transistors and the sense amp.
|
||||
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
|
||||
array_load = drain_load*self.words_per_row
|
||||
return [self.mux.analytical_delay(corner, slew, load+array_load)]
|
||||
|
||||
def get_drain_cin(self):
|
||||
"""Get the relative capacitance of the drain of the NMOS pass TX"""
|
||||
from tech import parameter
|
||||
|
||||
@@ -12,7 +12,7 @@ from tech import GDS,layer
|
||||
|
||||
class tri_gate(design.design):
|
||||
"""
|
||||
This module implements the tri gate cell used in the design for
|
||||
This module implements the tri gate cell used in the design forS
|
||||
bit-line isolation. It is a hand-made cell, so the layout and
|
||||
netlist should be available in the technology library.
|
||||
"""
|
||||
@@ -36,19 +36,13 @@ class tri_gate(design.design):
|
||||
self.pin_map = tri_gate.pin_map
|
||||
self.add_pin_types(self.type_list)
|
||||
|
||||
def analytical_delay(self, corner, slew, load=0.0):
|
||||
from tech import spice
|
||||
r = spice["min_tx_r"]
|
||||
c_para = spice["min_tx_drain_c"]
|
||||
return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
|
||||
|
||||
def analytical_power(self, corner, load):
|
||||
"""Returns dynamic and leakage power. Results in nW"""
|
||||
#Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
|
||||
total_power = self.return_power()
|
||||
return total_power
|
||||
|
||||
def input_load(self):
|
||||
def get_cin(self):
|
||||
return 9*spice["min_tx_gate_c"]
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
|
||||
@@ -120,10 +120,4 @@ class tri_gate_array(design.design):
|
||||
layer="metal1",
|
||||
offset=enbar_pin.ll().scale(0, 1),
|
||||
width=width,
|
||||
height=drc("minwidth_metal1"))
|
||||
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load=0.0):
|
||||
return self.tri.analytical_delay(corner, slew = slew, load = load)
|
||||
|
||||
height=drc("minwidth_metal1"))
|
||||
@@ -210,21 +210,6 @@ class wordline_driver(design.design):
|
||||
start=wl_offset,
|
||||
end=wl_offset-vector(self.m1_width,0))
|
||||
|
||||
|
||||
def analytical_delay(self, corner, slew, load=0):
|
||||
# decode -> net
|
||||
decode_t_net = self.nand2.analytical_delay(corner, slew, self.inv.input_load())
|
||||
|
||||
# net -> wl
|
||||
net_t_wl = self.inv.analytical_delay(corner, decode_t_net.slew, load)
|
||||
|
||||
return decode_t_net + net_t_wl
|
||||
|
||||
|
||||
def input_load(self):
|
||||
"""Gets the capacitance of the wordline driver in absolute units (fF)"""
|
||||
return self.nand2.input_load()
|
||||
|
||||
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
|
||||
"""Follows the clk_buf to a wordline signal adding each stages stage effort to a list"""
|
||||
stage_effort_list = []
|
||||
|
||||
Reference in New Issue
Block a user