From 8f28f4fde5c4bdce1faab25c863dcd0696560d71 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 16 Nov 2018 15:03:12 -0800 Subject: [PATCH 01/12] Don't always add all 3 types of contorl. Add write and read only port lists. --- compiler/base/design.py | 6 ++++++ compiler/sram_base.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/base/design.py b/compiler/base/design.py index 43957cb6..f52aa100 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -65,8 +65,12 @@ class design(hierarchy_design): self.readwrite_ports = [] # These are the read/write and write-only port indices self.write_ports = [] + # These are the write-only port indices. + self.writeonly_ports = [] # These are teh read/write and read-only port indice self.read_ports = [] + # These are the read-only port indices. + self.readonly_ports = [] # These are all the ports self.all_ports = list(range(total_ports)) @@ -78,9 +82,11 @@ class design(hierarchy_design): port_number += 1 for port in range(OPTS.num_w_ports): self.write_ports.append(port_number) + self.writeonly_ports.append(port_number) port_number += 1 for port in range(OPTS.num_r_ports): self.read_ports.append(port_number) + self.readonly_ports.append(port_number) port_number += 1 def analytical_power(self, proc, vdd, temp, load): diff --git a/compiler/sram_base.py b/compiler/sram_base.py index 879c4a04..29c3cbb9 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -226,12 +226,12 @@ class sram_base(design): words_per_row=self.words_per_row, port_type="rw") self.add_mod(self.control_logic_rw) - if len(self.write_ports)>0: + if len(self.writeonly_ports)>0: self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="w") self.add_mod(self.control_logic_w) - if len(self.read_ports)>0: + if len(self.readonly_ports)>0: self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="r") From b89c011e41d9b0a0677017a77f9f3354b792e36e Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 16 Nov 2018 15:31:22 -0800 Subject: [PATCH 02/12] Add psram 1w/1r test. Fix bl/br port naming errors in bank. --- compiler/modules/bank.py | 61 ++++++++++--------- .../tests/20_psram_1bank_2mux_1w_1r_test.py | 44 +++++++++++++ 2 files changed, 76 insertions(+), 29 deletions(-) create mode 100755 compiler/tests/20_psram_1bank_2mux_1w_1r_test.py diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 3a2d3f54..0f5deee2 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -877,9 +877,9 @@ class bank(design.design): if self.col_addr_size==0: return - bottom_inst = self.column_mux_array_inst[port] - top_inst = self.precharge_array_inst[port] - self.connect_bitlines(top_inst, bottom_inst, self.num_cols) + inst1 = self.column_mux_array_inst[port] + inst2 = self.precharge_array_inst[port] + self.connect_bitlines(inst1, inst2, self.num_cols) def route_column_mux_to_bitcell_array(self, port): """ Routing of BL and BR between col mux bitcell array """ @@ -888,47 +888,50 @@ class bank(design.design): if self.col_addr_size==0: return - bottom_inst = self.column_mux_array_inst[port] - top_inst = self.bitcell_array_inst - self.connect_bitlines(top_inst, bottom_inst, self.num_cols) + inst2 = self.column_mux_array_inst[port] + inst1 = self.bitcell_array_inst + inst1_bl_name = self.bl_names[port]+"_{}" + inst1_br_name = self.br_names[port]+"_{}" + self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols, + inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) def route_sense_amp_to_column_mux_or_precharge_array(self, port): """ Routing of BL and BR between sense_amp and column mux or precharge array """ - bottom_inst = self.sense_amp_array_inst[port] + inst2 = self.sense_amp_array_inst[port] if self.col_addr_size>0: # Sense amp is connected to the col mux - top_inst = self.column_mux_array_inst[port] - top_bl = "bl_out_{}" - top_br = "br_out_{}" + inst1 = self.column_mux_array_inst[port] + inst1_bl_name = "bl_out_{}" + inst1_br_name = "br_out_{}" else: # Sense amp is directly connected to the precharge array - top_inst = self.precharge_array_inst[port] - top_bl = "bl_{}" - top_br = "br_{}" + inst1 = self.precharge_array_inst[port] + inst1_bl_name = "bl_{}" + inst1_br_name = "br_{}" - self.connect_bitlines(inst1=top_inst, inst2=bottom_inst, num_bits=self.word_size, - inst1_bl_name=top_bl, inst1_br_name=top_br) + self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, + inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) - def route_write_driver_to_column_mux_or_precharge_array(self, port): - """ Routing of BL and BR between sense_amp and column mux or precharge array """ - bottom_inst = self.write_driver_array_inst[port] + def route_write_driver_to_column_mux_or_bitcell_array(self, port): + """ Routing of BL and BR between sense_amp and column mux or bitcell array """ + inst2 = self.write_driver_array_inst[port] if self.col_addr_size>0: - # Sense amp is connected to the col mux - top_inst = self.column_mux_array_inst[port] - top_bl = "bl_out_{}" - top_br = "br_out_{}" + # Write driver is connected to the col mux + inst1 = self.column_mux_array_inst[port] + inst1_bl_name = "bl_out_{}" + inst1_br_name = "br_out_{}" else: - # Sense amp is directly connected to the precharge array - top_inst = self.precharge_array_inst[port] - top_bl = "bl_{}" - top_br = "br_{}" + # Write driver is directly connected to the bitcell array + inst1 = self.bitcell_array_inst + inst1_bl_name = self.bl_names[port]+"_{}" + inst1_br_name = self.br_names[port]+"_{}" - self.connect_bitlines(inst1=top_inst, inst2=bottom_inst, num_bits=self.word_size, - inst1_bl_name=top_bl, inst1_br_name=top_br) + self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, + inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) def route_write_driver_to_sense_amp(self, port): """ Routing of BL and BR between write driver and sense amp """ @@ -943,7 +946,7 @@ class bank(design.design): for bit in range(self.word_size): data_pin = self.sense_amp_array_inst[port].get_pin("data_{}".format(bit)) - self.add_layout_pin_rect_center(text="dout{0}_{1}".format(self.read_ports[port],bit), + self.add_layout_pin_rect_center(text="dout{0}_{1}".format(port,bit), layer=data_pin.layer, offset=data_pin.center(), height=data_pin.height(), diff --git a/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py new file mode 100755 index 00000000..223cb6ed --- /dev/null +++ b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +""" +Run a regression test on a 1 bank SRAM +""" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +from globals import OPTS +import debug + +#@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete") +class psram_1bank_2mux_test(openram_test): + + def runTest(self): + globals.init_openram("config_20_{0}".format(OPTS.tech_name)) + from sram import sram + from sram_config import sram_config + OPTS.bitcell = "pbitcell" + OPTS.replica_bitcell="replica_pbitcell" + + OPTS.num_rw_ports = 0 + OPTS.num_w_ports = 1 + OPTS.num_r_ports = 1 + + c = sram_config(word_size=4, + num_words=32, + num_banks=1) + c.num_words=32 + c.words_per_row=2 + debug.info(1, "Single bank two way column mux 1w/1r with control logic") + a = sram(c, "sram") + self.local_check(a, final_verification=True) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() From 047d6ca2ef43e64c369a5e02d03d5158666ca4fe Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 16 Nov 2018 16:21:31 -0800 Subject: [PATCH 03/12] Must channel rout the column mux bits since they could overlap --- compiler/modules/bank.py | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 0f5deee2..8014b81c 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -930,8 +930,8 @@ class bank(design.design): inst1_bl_name = self.bl_names[port]+"_{}" inst1_br_name = self.br_names[port]+"_{}" - self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, - inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) + self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, + inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name) def route_write_driver_to_sense_amp(self, port): """ Routing of BL and BR between write driver and sense amp """ @@ -972,6 +972,37 @@ class bank(design.design): din_name = "din{0}_{1}".format(port,row) self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name) + def channel_route_bitlines(self, inst1, inst2, num_bits, + inst1_bl_name="bl_{}", inst1_br_name="br_{}", + inst2_bl_name="bl_{}", inst2_br_name="br_{}"): + """ + Route the bl and br of two modules using the channel router. + """ + + # determine top and bottom automatically. + # since they don't overlap, we can just check the bottom y coordinate. + if inst1.by() < inst2.by(): + (bottom_inst, bottom_bl_name, bottom_br_name) = (inst1, inst1_bl_name, inst1_br_name) + (top_inst, top_bl_name, top_br_name) = (inst2, inst2_bl_name, inst2_br_name) + else: + (bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name) + (top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name) + + + # Channel route each mux separately since we don't minimize the number + # of tracks in teh channel router yet. If we did, we could route all the bits at once! + offset = bottom_inst.ul() + vector(0,self.m1_pitch) + for bit in range(num_bits): + bottom_names = [bottom_bl_name.format(bit), bottom_br_name.format(bit)] + top_names = [top_bl_name.format(bit), top_br_name.format(bit)] + route_map = list(zip(bottom_names, top_names)) + bottom_pins = {key: bottom_inst.get_pin(key) for key in bottom_names } + top_pins = {key: top_inst.get_pin(key) for key in top_names } + all_pins = {**bottom_pins, **top_pins} + debug.check(len(all_pins)==len(bottom_pins)+len(top_pins),"Duplicate named pins in bitline channel route.") + self.create_horizontal_channel_route(route_map, all_pins, offset) + + def connect_bitlines(self, inst1, inst2, num_bits, inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst2_bl_name="bl_{}", inst2_br_name="br_{}"): From c677efa217becd9d780b7e7c3c0da4ffa659cf31 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Sun, 18 Nov 2018 09:15:03 -0800 Subject: [PATCH 04/12] Fix control logic center location. Fix rail height error in write only control logic. --- compiler/modules/control_logic.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 31e239a4..98a2496d 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -45,7 +45,6 @@ class control_logic(design.design): def create_layout(self): """ Create layout and route between modules """ - self.route_rails() self.place_instances() self.route_all() @@ -149,7 +148,7 @@ class control_logic(design.design): def route_rails(self): """ Add the input signal inverted tracks """ - height = 4*self.inv1.height - self.m2_pitch + height = self.control_logic_center.y - self.m2_pitch offset = vector(self.ctrl_dff_array.width,0) self.rail_offsets = self.create_vertical_bus("metal2", self.m2_pitch, offset, self.internal_bus_list, height) @@ -182,21 +181,21 @@ class control_logic(design.design): row += 2 if (self.port_type == "rw") or (self.port_type == "w"): self.place_we_row(row=row) - pre_height = self.w_en_inst.uy() - control_center_y = self.w_en_inst.by() + 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"): self.place_rbl_in_row(row=row) self.place_sen_row(row=row+1) self.place_rbl(row=row+2) - pre_height = self.rbl_inst.uy() + height = self.rbl_inst.uy() control_center_y = self.rbl_inst.by() # This offset is used for placement of the control logic in the SRAM level. self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y) # Extra pitch on top and right - self.height = pre_height + self.m3_pitch + self.height = height + self.m2_pitch # Max of modules or logic rows if (self.port_type == "rw") or (self.port_type == "r"): self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch @@ -205,6 +204,7 @@ class control_logic(design.design): def route_all(self): """ Routing between modules """ + self.route_rails() self.route_dffs() if (self.port_type == "rw") or (self.port_type == "w"): self.route_wen() From ba8bec3f6794afefd75e82f8ec3e230c2f8e9fab Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Sun, 18 Nov 2018 09:30:27 -0800 Subject: [PATCH 05/12] Two m1 pitches at top of control logic --- compiler/modules/control_logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 98a2496d..d227dfce 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -195,7 +195,7 @@ class control_logic(design.design): self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y) # Extra pitch on top and right - self.height = height + self.m2_pitch + self.height = height + 2*self.m1_pitch # Max of modules or logic rows if (self.port_type == "rw") or (self.port_type == "r"): self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch From 7709d5caa75e4bfc5c1e58729f09d218d3923ad9 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Sun, 18 Nov 2018 10:02:08 -0800 Subject: [PATCH 06/12] Move row addr dffs to top of bank to prevent addr route problems --- compiler/sram_1bank.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/sram_1bank.py b/compiler/sram_1bank.py index e1983ac5..896dcf6b 100644 --- a/compiler/sram_1bank.py +++ b/compiler/sram_1bank.py @@ -73,8 +73,9 @@ class sram_1bank(sram_base): self.control_logic_insts[port].place(control_pos[port]) # The row address bits are placed above the control logic aligned on the right. + # Or just below the top of the bank, whichever is greater. row_addr_pos[port] = vector(self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width, - self.control_logic_insts[port].uy()) + max(self.control_logic_insts[port].uy(), self.bank_inst.ul().y - self.row_addr_dff_insts[port].height)) self.row_addr_dff_insts[port].place(row_addr_pos[port]) # Add the col address flops below the bank to the left of the lower-left of bank array @@ -103,8 +104,9 @@ class sram_1bank(sram_base): self.control_logic_insts[port].place(control_pos[port], mirror="MY") # The row address bits are placed above the control logic aligned on the left. + # Or just below the top of the bank, whichever is greater. row_addr_pos[port] = vector(control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width, - self.control_logic_insts[port].uy()) + max(self.control_logic_insts[port].uy(), self.bank_inst.ul().y - self.row_addr_dff_insts[port].height)) self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="MY") # Add the col address flops above the bank to the right of the upper-right of bank array From 4630f52de2ffede1f5a2fba2f76a2280174b8135 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 19 Nov 2018 08:41:26 -0800 Subject: [PATCH 07/12] Use array ur instead of bank ur to pace row addr dff --- README.md | 4 ++-- compiler/modules/bank.py | 3 +-- compiler/sram_1bank.py | 14 ++++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 03b7213f..91e00bbd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # OpenRAM -Stable: [![pipeline status](https://scone.soe.ucsc.edu:8888/mrg/PrivateRAM/badges/master/pipeline.svg?private_token=ynB6rSFLzvKUseoBPcwV)](https://github.com/VLSIDA/PrivateRAM/commits/master) -Unstable: [![pipeline status](https://scone.soe.ucsc.edu:8888/mrg/PrivateRAM/badges/dev/pipeline.svg?private_token=ynB6rSFLzvKUseoBPcwV)](https://github.com/VLSIDA/PrivateRAM/commits/dev) +Master: [![pipeline status](https://scone.soe.ucsc.edu:8888/mrg/PrivateRAM/badges/master/pipeline.svg?private_token=ynB6rSFLzvKUseoBPcwV)](https://github.com/VLSIDA/PrivateRAM/commits/master) +Dev: [![pipeline status](https://scone.soe.ucsc.edu:8888/mrg/PrivateRAM/badges/dev/pipeline.svg?private_token=ynB6rSFLzvKUseoBPcwV)](https://github.com/VLSIDA/PrivateRAM/commits/dev) [![Download](images/download.svg)](https://github.com/VLSIDA/PrivateRAM/archive/master.zip) [![License: BSD 3-clause](./images/license_badge.svg)](./LICENSE) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 8014b81c..c4f4d557 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -65,8 +65,7 @@ class bank(design.design): self.bank_array_ur = self.bitcell_array_inst.ur() self.DRC_LVS() - - + def add_pins(self): """ Adding pins for Bank module""" for port in self.read_ports: diff --git a/compiler/sram_1bank.py b/compiler/sram_1bank.py index 896dcf6b..49ad4f9b 100644 --- a/compiler/sram_1bank.py +++ b/compiler/sram_1bank.py @@ -73,9 +73,10 @@ class sram_1bank(sram_base): self.control_logic_insts[port].place(control_pos[port]) # The row address bits are placed above the control logic aligned on the right. - # Or just below the top of the bank, whichever is greater. - row_addr_pos[port] = vector(self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width, - max(self.control_logic_insts[port].uy(), self.bank_inst.ul().y - self.row_addr_dff_insts[port].height)) + 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) + row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_dff_insts[port].place(row_addr_pos[port]) # Add the col address flops below the bank to the left of the lower-left of bank array @@ -104,9 +105,10 @@ class sram_1bank(sram_base): self.control_logic_insts[port].place(control_pos[port], mirror="MY") # The row address bits are placed above the control logic aligned on the left. - # Or just below the top of the bank, whichever is greater. - row_addr_pos[port] = vector(control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width, - max(self.control_logic_insts[port].uy(), self.bank_inst.ul().y - self.row_addr_dff_insts[port].height)) + 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 = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.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="MY") # Add the col address flops above the bank to the right of the upper-right of bank array From 6a7d721562d2804b4e85ffb26126eacca7c03308 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 19 Nov 2018 09:28:29 -0800 Subject: [PATCH 08/12] Add new bbox routine for pin enclosures --- compiler/base/pin_layout.py | 20 ++++++++++++++++++++ compiler/router/pin_group.py | 9 +++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index c1e6d79a..417bd6af 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -62,6 +62,26 @@ class pin_layout: else: return False + def bbox(self, pin_list): + """ + Given a list of layout pins, create a bounding box layout. + """ + (ll, ur) = self.rect + min_x = ll.x + max_x = ur.x + min_y = ll.y + max_y = ur.y + + filtered_list = [x for x in pin_list if x != None] + debug.check(len(filtered_list)>0,"Cannot find bbox of empty list.") + for pin in filtered_list: + min_x = min(min_x, pin.ll().x) + max_x = max(max_x, pin.ur().x) + min_y = min(min_y, pin.ll().y) + max_y = max(max_y, pin.ur().y) + + self.rect = [vector(min_x,min_y),vector(max_x,max_y)] + def inflate(self, spacing=None): """ Inflate the rectangle by the spacing (or other rule) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 695a5432..bb147ab1 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -464,14 +464,15 @@ class pin_group: # If it is contained, it won't need a connector if pin.contained_by_any(self.enclosures): continue - + left_connector = self.find_left_connector(pin, self.enclosures) right_connector = self.find_right_connector(pin, self.enclosures) above_connector = self.find_above_connector(pin, self.enclosures) below_connector = self.find_below_connector(pin, self.enclosures) - for connector in [left_connector, right_connector, above_connector, below_connector]: - if connector: - self.enclosures.append(connector) + import copy + bbox_connector = copy.copy(pin) + bbox_connector.bbox([left_connector, right_connector, above_connector, below_connector]) + self.enclosures.append(bbox_connector) # Now, make sure each pin touches an enclosure. If not, add a connector. # This could only happen when there was no enclosure in any cardinal direction from a pin From a47509de26d3dd82f64bf059dce4c4bd79e8ab68 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 19 Nov 2018 15:42:22 -0800 Subject: [PATCH 09/12] Move via away from cell edges --- compiler/modules/hierarchical_predecode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 72d0d99f..85ead465 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -267,7 +267,7 @@ class hierarchical_predecode(design.design): # Find the x offsets for where the vias/pins should be placed in_xoffset = self.in_inst[0].rx() - out_xoffset = self.inv_inst[0].lx() + out_xoffset = self.inv_inst[0].lx() - self.m1_space for num in range(0,self.number_of_outputs): # this will result in duplicate polygons for rails, but who cares From 2694ee1a4c22febb077cd1e83b1c49194247ddd4 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 19 Nov 2018 15:43:19 -0800 Subject: [PATCH 10/12] Add all insufficient grids that overlap the pin at all --- compiler/router/router.py | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/compiler/router/router.py b/compiler/router/router.py index 727d7753..68ff2d00 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -523,35 +523,51 @@ class router(router_tech): zindex=self.get_zindex(pin.layer_num) for x in range(int(ll[0])+expansion,int(ur[0])+1+expansion): for y in range(int(ll[1]+expansion),int(ur[1])+1+expansion): - debug.info(4,"Converting [ {0} , {1} ]".format(x,y)) (full_overlap,partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex)) if full_overlap: sufficient_list.update([full_overlap]) if partial_overlap: insufficient_list.update([partial_overlap]) + debug.info(4,"Converting [ {0} , {1} ] full={2} partial={3}".format(x,y, full_overlap, partial_overlap)) + if len(sufficient_list)>0: return sufficient_list elif expansion==0 and len(insufficient_list)>0: - #Remove blockages and return the best to be patched + #Remove blockages and return any overlap insufficient_list.difference_update(self.blocked_grids) - return self.get_best_offgrid_pin(pin, insufficient_list) + best_pin = self.get_all_offgrid_pin(pin, insufficient_list) + return best_pin elif expansion>0: #Remove blockages and return the nearest insufficient_list.difference_update(self.blocked_grids) - return self.get_nearest_offgrid_pin(pin, insufficient_list) + nearest_pin = self.get_nearest_offgrid_pin(pin, insufficient_list) + return nearest_pin else: debug.error("Unable to find any overlapping grids.", -1) + def get_all_offgrid_pin(self, pin, insufficient_list): + """ + Find a list of all pins with some overlap. + """ + #print("INSUFFICIENT LIST",insufficient_list) + # Find the coordinate with the most overlap + any_overlap = set() + for coord in insufficient_list: + full_pin = self.convert_track_to_pin(coord) + # Compute the overlap with that rectangle + overlap_rect=pin.compute_overlap(full_pin) + # Determine the max x or y overlap + max_overlap = max(overlap_rect) + if max_overlap>0: + any_overlap.update([coord]) + + return any_overlap + def get_best_offgrid_pin(self, pin, insufficient_list): """ - Given a pin and a list of partial overlap grids: - 1) Find the unblocked grids. - 2) If one, use it. - 3) If not, find the greatest overlap. - 4) Add a pin with the most overlap to make it "on grid" - that is not blocked. + Find a list of the single pin with the most overlap. """ #print("INSUFFICIENT LIST",insufficient_list) # Find the coordinate with the most overlap @@ -568,7 +584,7 @@ class router(router_tech): best_coord=coord return set([best_coord]) - + def get_nearest_offgrid_pin(self, pin, insufficient_list): """ Given a pin and a list of grid cells (probably non-overlapping), From 20d4e390f6ac35859dd2eac76c791d799b8ccfec Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 19 Nov 2018 15:45:07 -0800 Subject: [PATCH 11/12] Add bounding box of connector for when there are multiple connectors --- compiler/base/pin_layout.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 417bd6af..635366f9 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -72,9 +72,7 @@ class pin_layout: min_y = ll.y max_y = ur.y - filtered_list = [x for x in pin_list if x != None] - debug.check(len(filtered_list)>0,"Cannot find bbox of empty list.") - for pin in filtered_list: + for pin in pin_list: min_x = min(min_x, pin.ll().x) max_x = max(max_x, pin.ur().x) min_y = min(min_y, pin.ll().y) From b8299565eb588cb6e9df9bd15a9ef4c0ab7ee8f1 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 19 Nov 2018 17:32:55 -0800 Subject: [PATCH 12/12] Use grid furthest from blockages when blocked pin. Enclose multiple connectors. --- compiler/base/pin_layout.py | 2 +- compiler/router/grid_utils.py | 14 ++++++++++++++ compiler/router/pin_group.py | 24 ++++++++++++++++-------- compiler/router/router.py | 34 +++++++++++++++++++++++++--------- compiler/router/vector3d.py | 6 +++++- 5 files changed, 61 insertions(+), 19 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 635366f9..8f9e81ee 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -343,7 +343,7 @@ class pin_layout: (r2_ll,r2_ur) = other.rect def dist(x1, y1, x2, y2): - return sqrt((x2-x1)**2 + (y2-y1)**2) + return math.sqrt((x2-x1)**2 + (y2-y1)**2) left = r2_ur.x < r1_ll.x right = r1_ur.x < r2_ll.x diff --git a/compiler/router/grid_utils.py b/compiler/router/grid_utils.py index 23fe23ea..7ad864aa 100644 --- a/compiler/router/grid_utils.py +++ b/compiler/router/grid_utils.py @@ -3,6 +3,7 @@ Some utility functions for sets of grid cells. """ import debug +import math from direction import direction from vector3d import vector3d @@ -139,3 +140,16 @@ def flatten_set(curset): else: newset.update(flatten_set(c)) return newset + + + +def distance_set(coord, curset): + """ + Return the distance from a coordinate to any item in the set + """ + min_dist = math.inf + for c in curset: + min_dist = min(coord.euclidean_distance(c), min_dist) + + return min_dist + diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index bb147ab1..e50f94d9 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -465,16 +465,22 @@ class pin_group: if pin.contained_by_any(self.enclosures): continue + # Find a connector in the cardinal directions + # If there is overlap, but it isn't contained, these could all be None + # These could also be none if the pin is diagonal from the enclosure left_connector = self.find_left_connector(pin, self.enclosures) right_connector = self.find_right_connector(pin, self.enclosures) above_connector = self.find_above_connector(pin, self.enclosures) below_connector = self.find_below_connector(pin, self.enclosures) - import copy - bbox_connector = copy.copy(pin) - bbox_connector.bbox([left_connector, right_connector, above_connector, below_connector]) - self.enclosures.append(bbox_connector) + connector_list = [left_connector, right_connector, above_connector, below_connector] + filtered_list = list(filter(lambda x: x!=None, connector_list)) + if (len(filtered_list)>0): + import copy + bbox_connector = copy.copy(pin) + bbox_connector.bbox(filtered_list) + self.enclosures.append(bbox_connector) - # Now, make sure each pin touches an enclosure. If not, add a connector. + # Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector. # This could only happen when there was no enclosure in any cardinal direction from a pin for pin_list in self.pins: if not self.overlap_any_shape(pin_list, self.enclosures): @@ -596,7 +602,7 @@ class pin_group: # At least one of the groups must have some valid tracks if (len(pin_set)==0 and len(blockage_set)==0): - debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins)) + #debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins)) for pin_list in self.pins: for pin in pin_list: @@ -604,7 +610,7 @@ class pin_group: # Determine which tracks the pin overlaps pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin, expansion=1) pin_set.update(pin_in_tracks) - + if len(pin_set)==0: debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins)) self.router.write_debug_gds("blocked_pin.gds") @@ -650,7 +656,6 @@ class pin_group: that is ensured to overlap the supply rail wire. It then adds rectangle(s) for the enclosure. """ - additional_set = set() # Check the layer of any element in the pin to determine which direction to route it e = next(iter(start_set)) @@ -674,3 +679,6 @@ class pin_group: self.set_routed() self.enclosures = self.compute_enclosures() + + + diff --git a/compiler/router/router.py b/compiler/router/router.py index 68ff2d00..bb6e1efc 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -515,7 +515,7 @@ class router(router_tech): # scale the size bigger to include neaby tracks ll=ll.scale(self.track_factor).floor() ur=ur.scale(self.track_factor).ceil() - + #print(pin) # Keep tabs on tracks with sufficient and insufficient overlap sufficient_list = set() insufficient_list = set() @@ -529,23 +529,22 @@ class router(router_tech): if partial_overlap: insufficient_list.update([partial_overlap]) debug.info(4,"Converting [ {0} , {1} ] full={2} partial={3}".format(x,y, full_overlap, partial_overlap)) - + # Remove the blocked grids + sufficient_list.difference_update(self.blocked_grids) + insufficient_list.difference_update(self.blocked_grids) + if len(sufficient_list)>0: return sufficient_list elif expansion==0 and len(insufficient_list)>0: - #Remove blockages and return any overlap - insufficient_list.difference_update(self.blocked_grids) best_pin = self.get_all_offgrid_pin(pin, insufficient_list) + #print(best_pin) return best_pin elif expansion>0: - #Remove blockages and return the nearest - insufficient_list.difference_update(self.blocked_grids) - nearest_pin = self.get_nearest_offgrid_pin(pin, insufficient_list) + nearest_pin = self.get_furthest_offgrid_pin(pin, insufficient_list) return nearest_pin else: - debug.error("Unable to find any overlapping grids.", -1) - + return set() def get_all_offgrid_pin(self, pin, insufficient_list): """ @@ -585,6 +584,23 @@ class router(router_tech): return set([best_coord]) + def get_furthest_offgrid_pin(self, pin, insufficient_list): + """ + Get a grid cell that is the furthest from the blocked grids. + """ + + #print("INSUFFICIENT LIST",insufficient_list) + # Find the coordinate with the most overlap + best_coord = None + best_dist = math.inf + for coord in insufficient_list: + min_dist = grid_utils.distance_set(coord, self.blocked_grids) + if min_dist