SRAM with RBL integration in array.

This commit is contained in:
mrg 2019-07-16 09:04:58 -07:00
parent 37c15937e2
commit bea07c2319
4 changed files with 109 additions and 79 deletions

View File

@ -54,8 +54,8 @@ class bank(design.design):
def create_netlist(self):
self.compute_sizes()
self.add_pins()
self.add_modules()
self.add_pins() # Must create the replica bitcell array first
self.create_instances()
@ -78,9 +78,10 @@ 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),"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.read_ports:
self.add_pin(self.bitcell_array.get_rbl_bl_name(port),"OUT")
for port in self.read_ports:
self.add_pin(self.bitcell_array.get_rbl_wl_name(port),"IN")
for port in self.write_ports:
for bit in range(self.word_size):
self.add_pin("din{0}_{1}".format(port,bit),"IN")
@ -247,7 +248,7 @@ class bank(design.design):
# LOWER RIGHT QUADRANT
# To the left of the bitcell array
x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap
x_offset = self.bitcell_array_right + self.port_address.width
self.port_address_offsets[port] = vector(x_offset,self.main_bitcell_array_bottom)
# UPPER RIGHT QUADRANT
@ -684,11 +685,12 @@ class bank(design.design):
control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2*self.m1_pitch
control_bus_offset = vector(self.bitcell_array_right,
self.max_y_offset - control_bus_length)
# The bus for the right port is reversed so that the rbl_wl is closest to the array
self.bus_xoffset[1] = self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=control_bus_offset,
names=self.control_signals[1],
names=list(reversed(self.control_signals[1])),
length=control_bus_length,
vertical=True,
make_pins=(self.num_banks==1))
@ -950,13 +952,15 @@ class bank(design.design):
if port in self.read_ports:
connection.append((self.prefix+"s_en{}".format(port), self.port_data_inst[port].get_pin("s_en").lc()))
for (control_signal, pin_pos) in connection:
control_mid_pos = self.bus_xoffset[port][control_signal]
control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y)
self.add_path("metal1", [control_pos, pin_pos])
self.add_wire(("metal1","via1","metal2"), [control_mid_pos, control_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=control_pos)
# clk to wordline_driver
control_signal = self.prefix+"wl_en{}".format(port)
if port%2:

View File

@ -95,6 +95,18 @@ class control_logic(design.design):
size=4,
height=dff_height)
self.add_mod(self.and2)
if self.port_type=="rw":
self.rbl_driver = factory.create(module_type="pand2",
size=self.num_cols,
height=dff_height)
self.add_mod(self.rbl_driver)
elif self.port_type=="r":
self.rbl_driver = factory.create(module_type="pbuf",
size=self.num_cols,
height=dff_height)
self.add_mod(self.rbl_driver)
# clk_buf drives a flop for every address and control bit
# plus about 5 fanouts for the control logic
@ -131,12 +143,14 @@ class control_logic(design.design):
height=dff_height)
self.add_mod(self.inv)
# p_en_bar drives every column in the bicell array
# p_en_bar drives every column in the bitcell array
self.p_en_bar_driver = factory.create(module_type="pdriver",
neg_polarity=True,
fanout=self.num_cols,
height=dff_height)
self.add_mod(self.p_en_bar_driver)
# if (self.port_type == "rw") or (self.port_type == "r"):
# from importlib import reload
@ -366,11 +380,13 @@ class control_logic(design.design):
self.create_wlen_row()
if (self.port_type == "rw") or (self.port_type == "w"):
self.create_wen_row()
if (self.port_type == "rw") or (self.port_type == "r"):
if (self.port_type == "rw") or (self.port_type == "r"):
self.create_rbl_row()
self.create_pen_row()
self.create_sen_row()
self.create_delay()
if (self.port_type == "rw") or (self.port_type == "r") or self.words_per_row>1:
self.create_pen_row()
def place_instances(self):
@ -400,9 +416,10 @@ class control_logic(design.design):
height = self.w_en_inst.uy()
control_center_y = self.w_en_inst.uy()
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
if (self.port_type == "rw") or (self.port_type == "r") or self.words_per_row>1:
self.place_pen_row(row)
row += 1
self.place_sen_row(row)
@ -431,8 +448,9 @@ class control_logic(design.design):
self.route_wen()
if (self.port_type == "rw") or (self.port_type == "r"):
self.route_rbl()
self.route_pen()
self.route_sen()
if (self.port_type == "rw") or (self.port_type == "r") or self.words_per_row>1:
self.route_pen()
self.route_clk_buf()
self.route_gated_clk_bar()
self.route_gated_clk_buf()
@ -451,8 +469,8 @@ class control_logic(design.design):
# Add the RBL above the rows
# Add to the right of the control rows and routing channel
offset = vector(0, y_off)
self.delay_inst.place(offset)
offset = vector(self.delay_chain.width, y_off)
self.delay_inst.place(offset, mirror="MY")
def create_clk_buf_row(self):
@ -589,11 +607,15 @@ class control_logic(design.design):
self.connect_output(self.wl_en_inst, "Z", "wl_en")
def create_rbl_row(self):
# input: gated_clk_bar, we_bar, output: rbl_in
self.rbl_inst=self.add_inst(name="and2_rbl",
mod=self.and2)
self.connect_inst(["gated_clk_bar", "we_bar", "rbl_wl", "vdd", "gnd"])
self.rbl_inst=self.add_inst(name="rbl_driver",
mod=self.rbl_driver)
if self.port_type == "rw":
# input: gated_clk_bar, we_bar, output: rbl_wl
self.connect_inst(["gated_clk_bar", "we_bar", "rbl_wl", "vdd", "gnd"])
elif self.port_type == "r":
# input: gated_clk_bar, output: rbl_wl
self.connect_inst(["gated_clk_bar", "rbl_wl", "vdd", "gnd"])
def place_rbl_row(self,row):
x_off = self.control_x_offset
@ -608,20 +630,14 @@ class control_logic(design.design):
""" Connect the logic for the rbl_in generation """
if self.port_type == "rw":
input_name = "we_bar"
# Connect the NAND gate inputs to the bus
rbl_in_map = zip(["A", "B"], ["gated_clk_bar", "we_bar"])
self.connect_vertical_bus(rbl_in_map, self.rbl_inst, self.rail_offsets)
# Connect the output of the precharge enable to the RBL input
#if self.port_type == "rw":
# out_pos = self.rbl_in_inst.get_pin("Z").center()
#else:
# out_pos = vector(self.rail_offsets["gated_clk_bar"].x, self.rbl_inst.by()-3*self.m2_pitch)
self.copy_layout_pin(self.rbl_inst, "Z", "rbl_wl")
else:
rbl_in_map = zip(["A"], ["gated_clk_bar"])
self.connect_vertical_bus(rbl_in_map, self.rbl_inst, self.rail_offsets)
self.connect_output(self.rbl_inst, "Z", "rbl_wl")
# Input from RBL goes to the delay line for futher delay
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
def create_pen_row(self):
@ -727,7 +743,6 @@ class control_logic(design.design):
self.row_end_inst.append(self.w_en_inst)
def route_wen(self):
if self.port_type == "rw":
input_name = "we"
else:

View File

@ -99,13 +99,13 @@ class sram_1bank(sram_base):
# This includes 2 M2 pitches for the row addr clock line.
control_pos[port] = vector(-self.control_logic_insts[port].width - 2*self.m2_pitch,
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - self.bank.m2_gap)
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - 2*self.bank.m2_gap )
self.control_logic_insts[port].place(control_pos[port])
# The row address bits are placed above the control logic aligned on the right.
x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
# It is aove the control logic but below the top of the bitcell array
y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height)
# It is above the control logic but below the top of the bitcell array
y_offset = max(self.control_logic_insts[port].uy(), self.bank_inst.uy() - self.row_addr_dff_insts[port].height)
row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(row_addr_pos[port])
@ -137,6 +137,30 @@ class sram_1bank(sram_base):
# Port 1
port = 1
# Add the col address flops above the bank to the right of the upper-right of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
self.bank.height + max_gap_size + self.dff.height)
self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
else:
col_addr_pos[port] = self.bank_inst.ur()
# This includes 2 M2 pitches for the row addr clock line
control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2*self.m2_pitch,
self.bank.bank_array_ur.y + self.control_logic_insts[port].height -
(self.control_logic_insts[port].height - self.control_logic_insts[port].mod.control_logic_center.y)
+ 2*self.bank.m2_gap)
#import pdb; pdb.set_trace()
self.control_logic_insts[port].place(control_pos[port], mirror="XY")
# The row address bits are placed above the control logic aligned on the left.
x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
# It is below the control logic but below the bottom of the bitcell array
y_offset = min(self.control_logic_insts[port].by(), self.bank_inst.by() + self.row_addr_dff_insts[port].height)
row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY")
# Add the data flops above the bank to the left of the upper-right of bank array
# This relies on the upper-right of the array of the bank
# decoder in upper left, bank in upper right, sensing in lower right.
@ -153,29 +177,6 @@ class sram_1bank(sram_base):
wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.height + max_gap_size + self.data_dff_insts[port].height)
self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
else:
data_pos[port] = self.bank_inst.ur()
# Add the col address flops above the bank to the right of the upper-right of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
self.bank.height + max_gap_size + self.dff.height)
self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
else:
col_addr_pos[port] = self.bank_inst.ur()
# This includes 2 M2 pitches for the row addr clock line
control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2*self.m2_pitch,
self.bank.bank_array_ur.y + self.control_logic_insts[port].mod.control_logic_center.y + self.bank.m2_gap)
self.control_logic_insts[port].place(control_pos[port], mirror="XY")
# The row address bits are placed above the control logic aligned on the left.
x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
# It is above the control logic but below the top of the bitcell array
y_offset = min(self.control_logic_insts[port].by(), self.bank.bank_array_ll.y - self.row_addr_dff_insts[port].height)
row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY")
def add_layout_pins(self):
@ -271,20 +272,23 @@ class sram_1bank(sram_base):
def route_control_logic(self):
""" Route the outputs from the control logic module """
""" Route the control logic pins that are not inputs """
for port in self.all_ports:
for signal in self.control_logic_outputs[port]:
# The clock gets routed separately and is not a part of the bank
if "clk" in signal:
continue
if signal.startswith("rbl"):
continue
src_pin = self.control_logic_insts[port].get_pin(signal)
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
self.connect_rail_from_left_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"),
offset=src_pin.rc())
self.connect_vbus_m2m3(src_pin, dest_pin)
for port in self.read_ports:
# Only input (besides pins) is the replica bitline
src_pin = self.control_logic_insts[port].get_pin("rbl_bl")
dest_pin = self.bank_inst.get_pin("rbl_bl{}".format(port))
self.connect_vbus_m2m3(src_pin, dest_pin)
def route_row_addr_dff(self):
""" Connect the output of the row flops to the bank pins """

View File

@ -114,7 +114,7 @@ class sram_base(design, verilog, lef):
self.add_lvs_correspondence_points()
self.offset_all_coordinates()
#self.offset_all_coordinates()
highest_coord = self.find_highest_coords()
self.width = highest_coord[0]
@ -514,21 +514,28 @@ class sram_base(design, verilog, lef):
return insts
def connect_rail_from_left_m2m3(self, src_pin, dest_pin):
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
in_pos = src_pin.rc()
def connect_vbus_m2m3(self, src_pin, dest_pin):
""" Helper routine to connect an instance to a vertical bus.
Routes horizontal then vertical L shape.
Dest pin is assumed to be on M2.
Src pin can be on M1/M2/M3."""
if src_pin.cx()<dest_pin.cx():
in_pos = src_pin.rc()
else:
in_pos = src_pin.lc()
out_pos = dest_pin.center()
# move horizontal first
self.add_wire(("metal3","via2","metal2"),[in_pos, vector(out_pos.x,in_pos.y),out_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=src_pin.rc())
def connect_rail_from_left_m2m1(self, src_pin, dest_pin):
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
in_pos = src_pin.rc()
out_pos = vector(dest_pin.cx(), in_pos.y)
self.add_wire(("metal2","via1","metal1"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)])
if src_pin.layer=="metal1":
self.add_via_center(layers=("metal1","via1","metal2"),
offset=in_pos)
if src_pin.layer in ["metal1","metal2"]:
self.add_via_center(layers=("metal2","via2","metal3"),
offset=in_pos)
def sp_write(self, sp_name):
# Write the entire spice of the object to the file