diff --git a/compiler/base/channel_route.py b/compiler/base/channel_route.py index e1f9bedc..3afaf611 100644 --- a/compiler/base/channel_route.py +++ b/compiler/base/channel_route.py @@ -233,19 +233,10 @@ class channel_route(design): real_channel_offset = vector(self.offset.x, min(self.min_value, self.offset.y)) else: real_channel_offset = vector(min(self.min_value, self.offset.x), self.offset.y) - - if self.dff_area == False: - 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 - + current_offset = real_channel_offset + if self.dff_area == True: 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 - - 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 nets.sort() while len(nets) > 0: diff --git a/compiler/modules/sram_1bank.py b/compiler/modules/sram_1bank.py index 0c5056d0..6cc20605 100644 --- a/compiler/modules/sram_1bank.py +++ b/compiler/modules/sram_1bank.py @@ -280,10 +280,6 @@ class sram_1bank(design, verilog, lef): rtr.route_outside(io_pin_names=self.pins_to_route) # route moat vdds #rtr.route_moat(self.pins_to_route) - - # route to the outside - #rtr.prepare_escape_pins() - def route_supplies(self, bbox=None): """ 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 # 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 = y_offset + 0.4 # fix, maigc number self.row_addr_pos[port] = vector(x_offset, y_offset) 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. 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 - 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_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) if OPTS.route_supplies: - #self.route_supplies(init_bbox) - self.route_supplies_constructive(init_bbox) + if route_option == "classic": + self.route_supplies(init_bbox) + else: # fast + self.route_supplies_constructive(init_bbox) def route_dffs(self, add_routes=True): @@ -1175,7 +1172,7 @@ class sram_1bank(design, verilog, lef): if port == 0: 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, offset=offset, layer_stack=layer_stack, @@ -1228,17 +1225,11 @@ class sram_1bank(design, verilog, lef): route_map.extend(list(zip(bank_pins, dff_pins))) if len(route_map) > 0: - # This layer stack must be different than the column addr dff layer stack layer_stack = self.m2_stack if port == 0: - # This is relative to the bank at 0,0 or the s_en which is routed on M3 also - if "s_en" in self.control_logic_insts[port].mod.pin_map: - 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 + # for port 0, the offset of first track in channel router is fixed + y_offset = self.data_dff_insts[port].uy() + 6 * self.m3_pitch offset = vector(self.control_logic_insts[port].rx() + self.dff.width, y_offset) cr = channel_route(netlist=route_map, @@ -1253,13 +1244,77 @@ class sram_1bank(design, verilog, lef): self.connect_inst([]) # self.add_flat_inst(cr.name, cr) 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: - if "s_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()) + # for port1, the offset of first track in channel router needs to check first, make sure no overlap with control signal & address dff + 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: 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, y_offset) cr = channel_route(netlist=route_map, @@ -1274,7 +1329,10 @@ class sram_1bank(design, verilog, lef): self.connect_inst([]) # self.add_flat_inst(cr.name, cr) 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): """ Route the clock network """ diff --git a/compiler/router/io_pin_placer.py b/compiler/router/io_pin_placer.py index 27125dc3..f1f8dbf7 100644 --- a/compiler/router/io_pin_placer.py +++ b/compiler/router/io_pin_placer.py @@ -395,12 +395,15 @@ class io_pin_placer(router): return [source_pin.bc(), target_pin.uc()] else: # 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! 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: - 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_2 = vector(target_pin.center().x, via_basic_y) 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()] else: # 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: - 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: - 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_2 = vector(target_pin.center().x, via_basic_y) return [source_pin.uc(), point_1, point_2, target_pin.bc()] diff --git a/compiler/router/supply_placer.py b/compiler/router/supply_placer.py index e782b788..aa47ec5d 100644 --- a/compiler/router/supply_placer.py +++ b/compiler/router/supply_placer.py @@ -75,7 +75,7 @@ class supply_placer(router): selected_moat_pins = self.prepare_selected_moat_pins() # Route vdd and gnd 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]: if pin_name == gnd_name: # otherwise will not recognaize the moat blocakge self.prepare_gds_reader() @@ -206,7 +206,7 @@ class supply_placer(router): pin.ll(), pin.width(), pin.height()) - + 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 """ @@ -256,57 +256,6 @@ class supply_placer(router): 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): # 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 @@ -361,7 +310,7 @@ class supply_placer(router): self.moat_pins_bottom.append(moat_pin_route) elif edge == "top": 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) while pin_too_close: 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) else: # left shift 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 # the nearst vdd ring 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 "top" - + def find_closest_edge(self, pin): """ 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. # Specical handle gnd ring candidate_pins = [] - max_distance = 13 + max_distance = 20#13 if pin_name == "gnd": ring_pins = [] ring_pins = self.new_pins[pin_name] diff --git a/compiler/sram.py b/compiler/sram.py index f7e9b46d..98127aa6 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -114,7 +114,21 @@ class sram(): break elif self.route_option == "fast": 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: print_time("SRAM creation", datetime.datetime.now(), start_time) diff --git a/sram_compiler.py b/sram_compiler.py index e0727ea3..9d5fc4b3 100755 --- a/sram_compiler.py +++ b/sram_compiler.py @@ -70,7 +70,7 @@ for path in output_files: # Create an SRAM (we can also pass sram_config, see documentation/tutorials for details) 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 s.save()