Fix SRAM level control routing errors.

This commit is contained in:
Matt Guthaus 2018-11-28 15:30:52 -08:00
parent 143e4ed7f9
commit d99dcd33e2
5 changed files with 54 additions and 40 deletions

View File

@ -227,7 +227,7 @@ class bank(design.design):
# UPPER LEFT QUADRANT
# To the left of the bitcell array
# The wordline driver is placed to the right of the main decoder width.
x_offset = self.central_bus_width + self.wordline_driver.width
x_offset = self.m2_gap + self.wordline_driver.width
self.wordline_driver_offsets[port] = vector(-x_offset,0)
x_offset += self.row_decoder.width + self.m2_gap
self.row_decoder_offsets[port] = vector(-x_offset,0)
@ -284,7 +284,7 @@ class bank(design.design):
# LOWER RIGHT QUADRANT
# To the left of the bitcell array
# The wordline driver is placed to the right of the main decoder width.
x_offset = self.bitcell_array.width + self.central_bus_width + self.wordline_driver.width
x_offset = self.bitcell_array.width + self.m2_gap + self.wordline_driver.width
self.wordline_driver_offsets[port] = vector(x_offset,0)
x_offset += self.row_decoder.width + self.m2_gap
self.row_decoder_offsets[port] = vector(x_offset,0)
@ -350,21 +350,23 @@ class bank(design.design):
# FIXME: This spacing should be width dependent...
self.supply_rail_pitch = self.supply_rail_width + 4*self.m2_space
# Number of control lines in the bus
self.num_control_lines = 4
# The order of the control signals on the control bus:
self.input_control_signals = []
port_num = 0
for port in range(OPTS.num_rw_ports):
self.input_control_signals.append(["clk_buf{}".format(port_num), "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)])
port_num += 1
for port in range(OPTS.num_w_ports):
self.input_control_signals.append(["clk_buf{}".format(port_num), "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
for port in range(OPTS.num_r_ports):
self.input_control_signals.append(["clk_buf{}".format(port_num), "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)])
port_num += 1
# Number of control lines in the bus
self.num_control_lines = max([len(x) for x in self.input_control_signals])
# These will be outputs of the gaters if this is multibank, if not, normal signals.
self.control_signals = []
for port in self.all_ports:
@ -372,6 +374,7 @@ class bank(design.design):
self.control_signals.append(["gated_"+str for str in self.input_control_signals[port]])
else:
self.control_signals.append(self.input_control_signals[port])
# The central bus is the column address (one hot) and row address (binary)
if self.col_addr_size>0:
self.num_col_addr_lines = 2**self.col_addr_size
@ -380,7 +383,7 @@ class bank(design.design):
# The width of this bus is needed to place other modules (e.g. decoder)
# A width on each side too
self.central_bus_width = self.m2_pitch * self.num_control_lines + self.m2_width
#self.central_bus_width = self.m2_pitch * self.num_control_lines + self.m2_width
# A space for wells or jogging m2
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
@ -837,7 +840,8 @@ class bank(design.design):
# The bank is at (0,0), so this is to the left of the y-axis.
# 2 pitches on the right for vias/jogs to access the inputs
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset)
control_bus_length = self.max_y_offset - self.min_y_offset
# The control bus is routed up to two pitches below the bitcell array
control_bus_length = -2*self.m1_pitch - self.min_y_offset
self.bus_xoffset[0] = self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=control_bus_offset,
@ -849,6 +853,8 @@ class bank(design.design):
# Port 1
if len(self.all_ports)==2:
control_bus_offset = vector(self.bitcell_array.width + self.m2_width, self.min_y_offset)
# The other control bus is routed up to two pitches above the bitcell array
control_bus_length = self.max_y_offset + self.bitcell_array.height + 2*self.m1_pitch
self.bus_xoffset[1] = self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=control_bus_offset,
@ -1226,9 +1232,9 @@ class bank(design.design):
rotate=90)
# clk to wordline_driver
control_signal = self.prefix+"p_en_bar{}".format(port)
control_signal = self.prefix+"wl_en{}".format(port)
pin_pos = self.wordline_driver_inst[port].get_pin("en_bar").bc()
mid_pos = pin_pos - vector(0,self.m1_pitch)
mid_pos = pin_pos - vector(0,self.m2_gap) # to route down to the top of the bus
control_x_offset = self.bus_xoffset[port][control_signal].x
control_pos = vector(control_x_offset, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])

View File

@ -144,12 +144,12 @@ class control_logic(design.design):
self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch
# Outputs to the bank
if self.port_type == "r":
self.output_list = ["s_en", "p_en_bar"]
elif self.port_type == "w":
self.output_list = ["w_en"]
else:
if self.port_type == "rw":
self.output_list = ["s_en", "w_en", "p_en_bar"]
elif self.port_type == "r":
self.output_list = ["s_en", "p_en_bar"]
else:
self.output_list = ["w_en"]
self.output_list.append("wl_en")
self.output_list.append("clk_buf")

View File

@ -94,7 +94,7 @@ class precharge_array(design.design):
mod=self.pc_cell,
offset=offset)
self.local_insts.append(inst)
self.connect_inst(["bl_{0}".format(i), "br_{0}".format(i), "en", "vdd"])
self.connect_inst(["bl_{0}".format(i), "br_{0}".format(i), "en_bar", "vdd"])
def place_insts(self):

View File

@ -81,7 +81,7 @@ class sram_1bank(sram_base):
# Add the col address flops below the bank to the left of the lower-left of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.central_bus_width,
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
-data_gap - self.col_addr_dff_insts[port].height)
self.col_addr_dff_insts[port].place(col_addr_pos[port])
@ -178,27 +178,11 @@ class sram_1bank(sram_base):
# Connect all of these clock pins to the clock in the central bus
# This is something like a "spine" clock distribution. The two spines
# are clk_buf and clk_buf_bar
control_clk_buf_pin = self.control_logic_insts[port].get_pin("clk_buf")
control_clk_buf_pos = control_clk_buf_pin.center()
bank_clk_buf_pin = self.bank_inst.get_pin("clk_buf{}".format(port))
bank_clk_buf_pos = bank_clk_buf_pin.center()
bank_clk_buf_bar_pin = self.bank_inst.get_pin("clk_buf_bar{}".format(port))
bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center()
if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_insts[port].get_pin("clk")
dff_clk_pos = dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos])
if port in self.write_ports:
data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos])
# This uses a metal2 track to the right (for port0) of the control/row addr DFF
# to route vertically. For port1, it is to the left.
control_clk_buf_pin = self.control_logic_insts[port].get_pin("clk_buf")
row_addr_clk_pin = self.row_addr_dff_insts[port].get_pin("clk")
if port%2:
control_clk_buf_pos = control_clk_buf_pin.lc()
@ -210,17 +194,38 @@ class sram_1bank(sram_base):
row_addr_clk_pos = row_addr_clk_pin.rc()
mid1_pos = vector(self.row_addr_dff_insts[port].rx() + self.m2_pitch,
row_addr_clk_pos.y)
mid2_pos = vector(mid1_pos.x,
control_clk_buf_pos.y)
# This is the steiner point where the net branches out
clk_steiner_pos = vector(mid1_pos.x, control_clk_buf_pos.y)
self.add_path("metal1", [control_clk_buf_pos, clk_steiner_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=clk_steiner_pos,
rotate=90)
# Note, the via to the control logic is taken care of when we route
# the control logic to the bank
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, mid2_pos, control_clk_buf_pos])
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, clk_steiner_pos, control_clk_buf_pos])
if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_insts[port].get_pin("clk")
dff_clk_pos = dff_clk_pin.center()
mid_pos = vector(clk_steiner_pos.x, dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, clk_steiner_pos])
if port in self.write_ports:
data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center()
mid_pos = vector(clk_steiner_pos.x, data_dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, clk_steiner_pos])
def route_control_logic(self):
""" Route the outputs from the control logic module """
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
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)

View File

@ -409,11 +409,14 @@ class sram_base(design):
mod = self.control_logic_r
insts.append(self.add_inst(name="control{}".format(port), mod=mod))
# Inputs
temp = ["csb{}".format(port)]
if port in self.readwrite_ports:
temp.append("web{}".format(port))
temp.append("clk{}".format(port))
# Ouputs
if port in self.read_ports:
temp.append("s_en{}".format(port))
if port in self.write_ports: