more stable

This commit is contained in:
FriedrichWu 2024-12-16 00:13:40 +01:00
parent 4fe635a05f
commit bda3adf9f9
6 changed files with 116 additions and 98 deletions

View File

@ -233,19 +233,10 @@ class channel_route(design):
real_channel_offset = vector(self.offset.x, min(self.min_value, self.offset.y)) real_channel_offset = vector(self.offset.x, min(self.min_value, self.offset.y))
else: else:
real_channel_offset = vector(min(self.min_value, self.offset.x), self.offset.y) real_channel_offset = vector(min(self.min_value, self.offset.x), self.offset.y)
current_offset = real_channel_offset
if self.dff_area == False: if self.dff_area == True:
current_offset = real_channel_offset
else: # special handle for dff area
current_offset = vector(real_channel_offset.x, real_channel_offset.y + 5) # make route out of dffs area
if self.layer_stack == self.m2_stack: if self.layer_stack == self.m2_stack:
self.vertical_nonpref_pitch = self.horizontal_pitch + 0.1 # 0.1 make sure even if via at same col, fulfill m3-m3 spacing self.vertical_nonpref_pitch = self.horizontal_pitch + 0.1 # 0.1 make sure even if via at same col, fulfill m3-m3 spacing
if self.layer_stack == self.m1_stack:
current_offset = vector(real_channel_offset.x, current_offset.y + 14) # make sure no overlap between col_dffs & data_dffs
if real_channel_offset.y > 0: # which means this is channnel router for coldff at the top
current_offset = real_channel_offset # no offset to avoid overlap problem at the top
# Sort nets by left edge value # Sort nets by left edge value
nets.sort() nets.sort()
while len(nets) > 0: while len(nets) > 0:

View File

@ -280,10 +280,6 @@ class sram_1bank(design, verilog, lef):
rtr.route_outside(io_pin_names=self.pins_to_route) rtr.route_outside(io_pin_names=self.pins_to_route)
# route moat vdds # route moat vdds
#rtr.route_moat(self.pins_to_route) #rtr.route_moat(self.pins_to_route)
# route to the outside
#rtr.prepare_escape_pins()
def route_supplies(self, bbox=None): def route_supplies(self, bbox=None):
""" Route the supply grid and connect the pins to them. """ """ Route the supply grid and connect the pins to them. """
@ -916,7 +912,6 @@ class sram_1bank(design, verilog, lef):
x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
# It is above the control logic and the predecoder array # It is above the control logic and the predecoder array
y_offset = max(self.control_logic_insts[port].uy(), self.bank.predecoder_top) y_offset = max(self.control_logic_insts[port].uy(), self.bank.predecoder_top)
y_offset = y_offset + 0.4 # fix, maigc number
self.row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(self.row_addr_pos[port]) self.row_addr_dff_insts[port].place(self.row_addr_pos[port])
@ -925,7 +920,7 @@ class sram_1bank(design, verilog, lef):
# The row address bits are placed above the control logic aligned on the left. # The row address bits are placed above the control logic aligned on the left.
x_offset = self.control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width x_offset = self.control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
# If it can be placed above the predecoder and below the control logic, do it # If it can be placed above the predecoder and below the control logic, do it
y_offset = min(self.control_logic_insts[port].by(), self.bank.predecoder_top) y_offset = min(self.control_logic_insts[port].by(), self.bank.predecoder_bottom)
self.row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(self.row_addr_pos[port], mirror="XY") self.row_addr_dff_insts[port].place(self.row_addr_pos[port], mirror="XY")
@ -1138,8 +1133,10 @@ class sram_1bank(design, verilog, lef):
self.route_escape_pins(bbox=init_bbox, mod=mod, route_option=route_option) self.route_escape_pins(bbox=init_bbox, mod=mod, route_option=route_option)
if OPTS.route_supplies: if OPTS.route_supplies:
#self.route_supplies(init_bbox) if route_option == "classic":
self.route_supplies_constructive(init_bbox) self.route_supplies(init_bbox)
else: # fast
self.route_supplies_constructive(init_bbox)
def route_dffs(self, add_routes=True): def route_dffs(self, add_routes=True):
@ -1175,7 +1172,7 @@ class sram_1bank(design, verilog, lef):
if port == 0: if port == 0:
offset = vector(self.control_logic_insts[port].rx() + self.dff.width, offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
- self.data_bus_size[port] + 2 * self.m3_pitch) self.bank_inst.by() - self.col_addr_size * self.m3_pitch)# higher offset to avoid possible overlap with data dffs channel routing
cr = channel_route(netlist=route_map, cr = channel_route(netlist=route_map,
offset=offset, offset=offset,
layer_stack=layer_stack, layer_stack=layer_stack,
@ -1228,17 +1225,11 @@ class sram_1bank(design, verilog, lef):
route_map.extend(list(zip(bank_pins, dff_pins))) route_map.extend(list(zip(bank_pins, dff_pins)))
if len(route_map) > 0: if len(route_map) > 0:
# This layer stack must be different than the column addr dff layer stack # This layer stack must be different than the column addr dff layer stack
layer_stack = self.m2_stack layer_stack = self.m2_stack
if port == 0: if port == 0:
# This is relative to the bank at 0,0 or the s_en which is routed on M3 also # for port 0, the offset of first track in channel router is fixed
if "s_en" in self.control_logic_insts[port].mod.pin_map: y_offset = self.data_dff_insts[port].uy() + 6 * self.m3_pitch
y_bottom = min(0, self.control_logic_insts[port].get_pin("s_en").by())
else:
y_bottom = 0
y_offset = y_bottom - self.data_bus_size[port] + 2 * self.m3_pitch
offset = vector(self.control_logic_insts[port].rx() + self.dff.width, offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
y_offset) y_offset)
cr = channel_route(netlist=route_map, cr = channel_route(netlist=route_map,
@ -1253,13 +1244,77 @@ class sram_1bank(design, verilog, lef):
self.connect_inst([]) self.connect_inst([])
# self.add_flat_inst(cr.name, cr) # self.add_flat_inst(cr.name, cr)
else: else:
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap # return the real channel width that min. should be
# the bottom of w_en or s_en
if ("s_en" in self.control_logic_insts[port].mod.pin_map) and ("w_en" in self.control_logic_insts[port].mod.pin_map):# rw
y_bottom = min(0, self.control_logic_insts[port].get_pin("s_en").by(), self.control_logic_insts[port].get_pin("w_en").by())
elif "w_en" in self.control_logic_insts[port].mod.pin_map:# w
y_bottom = min(0, self.control_logic_insts[port].get_pin("w_en").by())
else:
y_bottom = 0
if len(self.all_ports) == 1: # only 1 port at bottom
extra_offset = 6 * self.m3_pitch + (self.bank_inst.by() - (y_bottom - self.m4_nonpref_pitch))
else: # 2 ports, row address decoder needs to be considered
# for port 0
# determine the most right dffs
if self.num_spare_cols: # if we have spare regs
dff_right_x = self.spare_wen_dff_insts[0].rx()
else: # data dffs
dff_right_x = self.data_dff_insts[0].rx()
# check if row address dffs are overlaped with dff area, bank position as reference
if self.bank_inst.rx() < (dff_right_x + 2 * self.m4_pitch):
debug.warning("m4 pitch ----> {0}".format(self.m4_pitch))
debug.warning("m3 pitch ----> {0}".format(self.m3_pitch))
debug.warning("m4_non_pref pitch ----> {0}".format(self.m4_nonpref_pitch))
debug.warning("lower row addr dff: {0}".format(self.row_addr_dff_insts[1].by()))
debug.warning("higher row addr dff: {0}".format(self.row_addr_dff_insts[1].uy()))
# check the most lower one betwenn control signal and address dff
if y_bottom < self.row_addr_dff_insts[1].by():
y_bottom_most = y_bottom
else:
y_bottom_most = self.row_addr_dff_insts[1].by()
# the upper track should below the lower one
extra_offset = 6 * self.m3_pitch + (self.bank_inst.by() - (y_bottom_most - self.m4_nonpref_pitch))
else: # do not need take care of address dff 1, since it's far away
extra_offset = 6 * self.m3_pitch + (self.bank_inst.by() - (y_bottom - self.m4_nonpref_pitch))
debug.warning("extra_offset->{0}".format(extra_offset))
debug.warning("channel_height->{0}".format(cr.height))
debug.warning("self.col_addr_bus_size->{0}".format(self.col_addr_bus_size[port]))
debug.warning("self.databusgap->{0}".format(self.data_bus_gap))
self.data_bus_size[port] = max((cr.height + extra_offset), self.col_addr_bus_size[port]) + self.data_bus_gap
else: else:
if "s_en" in self.control_logic_insts[port].mod.pin_map: # for port1, the offset of first track in channel router needs to check first, make sure no overlap with control signal & address dff
y_top = max(self.bank.height, self.control_logic_insts[port].get_pin("s_en").uy()) if ("s_en" in self.control_logic_insts[port].mod.pin_map) and ("w_en" in self.control_logic_insts[port].mod.pin_map):
y_top = max(self.bank.height, self.control_logic_insts[port].get_pin("s_en").uy(), self.control_logic_insts[port].get_pin("w_en").uy())
y_offset = y_top + 6 * self.m3_pitch
elif "w_en" in self.control_logic_insts[port].mod.pin_map:
y_top = max(self.bank.height, self.control_logic_insts[port].get_pin("w_en").uy())
y_offset = y_top + self.m3_pitch# it's fine, since w port doesn't have dout signals
else: else:
y_top = self.bank.height y_top = self.bank.height
y_offset = y_top + self.m3_pitch y_offset = y_top + 6 * self.m3_pitch
# check the offset overlap with address dff 0 or not
if self.num_spare_cols: # if we have spare regs
dff_left_x = self.spare_wen_dff_insts[1].lx()
else: # data dffs
dff_left_x = self.data_dff_insts[1].lx()
# check if row address dffs are overlaped with dff area
if self.bank_inst.lx() > (dff_left_x - 2 * self.m4_pitch):
debug.warning("m4 pitch ----> {0}".format(self.m4_pitch))
debug.warning("m3 pitch ----> {0}".format(self.m3_pitch))
debug.warning("m4_non_pref pitch ----> {0}".format(self.m4_nonpref_pitch))
# the bottom track should also above row address decoder
if y_offset > self.row_addr_dff_insts[0].uy() + self.m4_nonpref_pitch:
# do not need change since first track is high enough
extra_offset = y_offset - self.bank.height # height could be use since bank at 0,0
else: # make it higher tham row address decoder
extra_offset = self.row_addr_dff_insts[0].uy() + self.m4_nonpref_pitch - self.bank_inst.height
# update the new y_offset
y_offset = self.row_addr_dff_insts[0].uy() + self.m4_nonpref_pitch
else: # do not need to take care address dff0, since it's far away
extra_offset = y_offset - self.bank.height # height could be use since bank at 0,0
offset = vector(0, offset = vector(0,
y_offset) y_offset)
cr = channel_route(netlist=route_map, cr = channel_route(netlist=route_map,
@ -1274,7 +1329,10 @@ class sram_1bank(design, verilog, lef):
self.connect_inst([]) self.connect_inst([])
# self.add_flat_inst(cr.name, cr) # self.add_flat_inst(cr.name, cr)
else: else:
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap # return the real channel width that min. should be
# 2 ports, row address decoder needs to be considered
# for port 1
self.data_bus_size[port] = max((cr.height + extra_offset), self.col_addr_bus_size[port]) + self.data_bus_gap
def route_clk(self): def route_clk(self):
""" Route the clock network """ """ Route the clock network """

View File

@ -395,12 +395,15 @@ class io_pin_placer(router):
return [source_pin.bc(), target_pin.uc()] return [source_pin.bc(), target_pin.uc()]
else: else:
# need intermediate point # need intermediate point
via_basic_y = self.design.bank.height + 3 # 3 is magic number, make sure out of bank area #via_basic_y = self.design.bank.height + 3 # 3 is magic number, make sure out of bank area
via_basic_y = self.design.bank_inst.uy() + 3 * self.design.m3_pitch
is_up = not is_up# Be attention, for channel at the top, the is_up should be inverted! Otherwise will cause overlap! is_up = not is_up# Be attention, for channel at the top, the is_up should be inverted! Otherwise will cause overlap!
if is_up: if is_up:
via_basic_y = via_basic_y + 0.5 #via_basic_y = via_basic_y + 0.5
via_basic_y = via_basic_y + self.design.m3_pitch
else: else:
via_basic_y = via_basic_y - 0.5 #via_basic_y = via_basic_y - 0.5
via_basic_y = via_basic_y - self.design.m3_pitch
point_1 = vector(source_pin.center().x, via_basic_y) point_1 = vector(source_pin.center().x, via_basic_y)
point_2 = vector(target_pin.center().x, via_basic_y) point_2 = vector(target_pin.center().x, via_basic_y)
return [source_pin.bc(), point_1, point_2, target_pin.uc()] return [source_pin.bc(), point_1, point_2, target_pin.uc()]
@ -412,11 +415,14 @@ class io_pin_placer(router):
return [source_pin.uc(), target_pin.bc()] return [source_pin.uc(), target_pin.bc()]
else: else:
# need intermediate point # need intermediate point
via_basic_y = ll.y + 22 # 22 is magic number, make sure out of dff area #via_basic_y = ll.y + 22 # 22 is magic number, make sure out of dff area
via_basic_y = self.design.data_dff_insts[0].uy() + 3 * self.design.m3_pitch
if is_up: if is_up:
via_basic_y = via_basic_y + 0.5 #via_basic_y = via_basic_y + 0.5
via_basic_y = via_basic_y + self.design.m3_pitch
else: else:
via_basic_y = via_basic_y - 0.5 #via_basic_y = via_basic_y - 0.5
via_basic_y = via_basic_y - self.design.m3_pitch
point_1 = vector(source_pin.center().x, via_basic_y) point_1 = vector(source_pin.center().x, via_basic_y)
point_2 = vector(target_pin.center().x, via_basic_y) point_2 = vector(target_pin.center().x, via_basic_y)
return [source_pin.uc(), point_1, point_2, target_pin.bc()] return [source_pin.uc(), point_1, point_2, target_pin.bc()]

View File

@ -75,7 +75,7 @@ class supply_placer(router):
selected_moat_pins = self.prepare_selected_moat_pins() selected_moat_pins = self.prepare_selected_moat_pins()
# Route vdd and gnd # Route vdd and gnd
routed_count = 0 routed_count = 0
routed_max = len(self.pins[vdd_name]) + len(self.pins[gnd_name]) routed_max = len(self.pins[vdd_name]) + len(self.pins[gnd_name]) + len(self.moat_pins) + len(self.new_pins["gnd"])
for pin_name in [vdd_name, gnd_name]: for pin_name in [vdd_name, gnd_name]:
if pin_name == gnd_name: # otherwise will not recognaize the moat blocakge if pin_name == gnd_name: # otherwise will not recognaize the moat blocakge
self.prepare_gds_reader() self.prepare_gds_reader()
@ -206,7 +206,7 @@ class supply_placer(router):
pin.ll(), pin.ll(),
pin.width(), pin.width(),
pin.height()) pin.height())
def prepare_selected_moat_pins(self): def prepare_selected_moat_pins(self):
""" Selcet the possibe moat pins, feed into the MST, where will decide which of these pin should be connected to which pin """ """ Selcet the possibe moat pins, feed into the MST, where will decide which of these pin should be connected to which pin """
@ -256,57 +256,6 @@ class supply_placer(router):
return selected_moat_pins return selected_moat_pins
def prepare_escape_pins(self):
# clear all the inside "vdd " "gnd" at sram module level
# Copy the pin shape(s) to rectangles
for pin_name in ["vdd", "gnd"]:
# Copy the pin shape(s) to rectangles
for pin in self.design.get_pins(pin_name):
self.design.add_rect(pin.layer,
pin.ll(),
pin.width(),
pin.height())
# Remove the pin shape(s)
self.design.remove_layout_pin(pin_name)
# prepare pins for every instances
for pin_name in ["vdd"]:
count =0
for pin in self.design.control_logic_insts[0].get_pins(pin_name):
debug.warning("vdd pin shape -> ll:{0} ur:{1}".format(pin.ll(), pin.ur()))
"""
count = count + 1
new_pin = graph_shape("gnd", pin.rect, pin.layer)
source = new_pin
source_center_x = pin.center().x
target_ur_y = self.new_pins[self.ext_gnd_name][1].center().y + 0.5 * self.new_pins[self.ext_gnd_name][1].height()
ll = vector(source_center_x - 2.6 - 0.5 * self.track_wire, pin.center().y - 0.5 * self.track_wire)#target_ur_y - self.track_wire)
ur = vector(source_center_x - 2.6 + 0.5 * self.track_wire, pin.center().y + 0.5 * self.track_wire)#target_ur_y)
target = graph_shape("fake", [ll,ur], pin.layer)
# Create the graph
g = graph(self)
g.create_graph(source, target)
# Find the shortest path from source to target
path = g.find_shortest_path()
# If no path is found, throw an error
if path is None:
self.write_debug_gds(gds_name="{}error.gds".format(OPTS.openram_temp), g=g, source=source, target=target)
debug.error("Couldn't route from {} to {}.".format(source, target), -1)
# Create the path shapes on layout
new_wires, new_vias = self.add_path(path)
# Find the recently added shapes
self.find_blockages(pin_name, new_wires)
self.find_vias(new_vias)
"""
debug.warning("vdd of wmask number -> {0}".format(count))
debug.warning("instance postion -> {0} {1}".format(self.design.control_logic_insts[0].lx(), self.design.control_logic_insts[0].by()))
# print pins_all
for pin in self.all_pins:
debug.warning("all_pins -> {0}".format(pin))
def check_overlap(self, moat_pin, io_pin_names): def check_overlap(self, moat_pin, io_pin_names):
# use all the IO pins(at correspoding edge) to check overlap, check 1 moat vdd pin, give the corresponding target/source position as list, and connect them # use all the IO pins(at correspoding edge) to check overlap, check 1 moat vdd pin, give the corresponding target/source position as list, and connect them
add_distance = 0 add_distance = 0
@ -361,7 +310,7 @@ class supply_placer(router):
self.moat_pins_bottom.append(moat_pin_route) self.moat_pins_bottom.append(moat_pin_route)
elif edge == "top": elif edge == "top":
add_distance = self.via2_via3_pitch # if shift, need to fulfill via2-via3 spacing, top/bottom only add_distance = self.via2_via3_pitch # if shift, need to fulfill via2-via3 spacing, top/bottom only
pin_too_close = any(abs(io_pin.center().x - source_center.x) < self.track_width for io_pin in self.io_pins_top) pin_too_close = any(abs(io_pin.center().x - source_center.x) < (self.track_width + 0.1) for io_pin in self.io_pins_top)
tmp_center = vector(source_center.x, source_center.y) tmp_center = vector(source_center.x, source_center.y)
while pin_too_close: while pin_too_close:
tmp_center = vector(source_center.x, source_center.y) tmp_center = vector(source_center.x, source_center.y)
@ -370,7 +319,7 @@ class supply_placer(router):
tmp_center = vector((tmp_center.x + add_distance), tmp_center.y) tmp_center = vector((tmp_center.x + add_distance), tmp_center.y)
else: # left shift else: # left shift
tmp_center = vector((tmp_center.x - add_distance), tmp_center.y) tmp_center = vector((tmp_center.x - add_distance), tmp_center.y)
pin_too_close = any(abs(io_pin.center().x - tmp_center.x) < self.track_width for io_pin in self.io_pins_top) pin_too_close = any(abs(io_pin.center().x - tmp_center.x) < (self.track_width + 0.1) for io_pin in self.io_pins_top)
direction = - direction direction = - direction
# the nearst vdd ring # the nearst vdd ring
vdd_ring = self.new_pins["vdd"][0] # order in list -> "top", "bottom", "right", "left"] vdd_ring = self.new_pins["vdd"][0] # order in list -> "top", "bottom", "right", "left"]
@ -628,7 +577,7 @@ class supply_placer(router):
return "right" return "right"
return "top" return "top"
def find_closest_edge(self, pin): def find_closest_edge(self, pin):
""" Use to find the edge, where the io pin locats """ """ Use to find the edge, where the io pin locats """
@ -796,7 +745,7 @@ class supply_placer(router):
# Prepare the pins that are allowed to connect to the moat pins. # Prepare the pins that are allowed to connect to the moat pins.
# Specical handle gnd ring # Specical handle gnd ring
candidate_pins = [] candidate_pins = []
max_distance = 13 max_distance = 20#13
if pin_name == "gnd": if pin_name == "gnd":
ring_pins = [] ring_pins = []
ring_pins = self.new_pins[pin_name] ring_pins = self.new_pins[pin_name]

View File

@ -114,7 +114,21 @@ class sram():
break break
elif self.route_option == "fast": elif self.route_option == "fast":
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.s.create_layout(route_option=route_option) i = 0
while i < 10:
debug.warning("current i: i = {0}".format(i))
try:
self.s.create_layout(position_add=i, route_option=route_option)
except AssertionError as e:
i = i + 1
if i == 9: #failed in routing
debug.error("Failed in routing", -1)
break
del self.s
self.s = sram(name, sram_config)
self.s.create_netlist()
continue
break
if not OPTS.is_unit_test: if not OPTS.is_unit_test:
print_time("SRAM creation", datetime.datetime.now(), start_time) print_time("SRAM creation", datetime.datetime.now(), start_time)

View File

@ -70,7 +70,7 @@ for path in output_files:
# Create an SRAM (we can also pass sram_config, see documentation/tutorials for details) # Create an SRAM (we can also pass sram_config, see documentation/tutorials for details)
from openram import sram from openram import sram
s = sram(route_option="fast")# "classic" or "fast" s = sram(route_option="classic")# "classic" or "fast"
# Output the files for the resulting SRAM # Output the files for the resulting SRAM
s.save() s.save()