mirror of https://github.com/VLSIDA/OpenRAM.git
SRAM with RBL integration in array.
This commit is contained in:
parent
37c15937e2
commit
bea07c2319
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 """
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue