From 7385decbff33b4f7c7992fd09919733586cdc04c Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Jul 2020 12:02:30 -0700 Subject: [PATCH 1/8] Add channel route cyclic VCG debugging. --- compiler/base/channel_route.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/compiler/base/channel_route.py b/compiler/base/channel_route.py index f2711222..61af303c 100644 --- a/compiler/base/channel_route.py +++ b/compiler/base/channel_route.py @@ -38,7 +38,7 @@ class channel_net(): def __lt__(self, other): return self.min_value < other.min_value - def vcg_pin_overlap(self, pin1, pin2, pitch): + def pin_overlap(self, pin1, pin2, pitch): """ Check for vertical or horizontal overlap of the two pins """ # FIXME: If the pins are not in a row, this may break. @@ -53,7 +53,7 @@ class channel_net(): overlaps = (not self.vertical and x_overlap) or (self.vertical and y_overlap) return overlaps - def vcg_nets_overlap(self, other, pitch): + def pins_overlap(self, other, pitch): """ Check all the pin pairs on two nets and return a pin overlap if any pin overlaps. @@ -61,12 +61,12 @@ class channel_net(): for pin1 in self.pins: for pin2 in other.pins: - if self.vcg_pin_overlap(pin1, pin2, pitch): + if self.pin_overlap(pin1, pin2, pitch): return True return False - def hcg_nets_overlap(self, other): + def segment_overlap(self, other): """ Check if the horizontal span of the two nets overlaps eachother. """ @@ -84,7 +84,8 @@ class channel_route(design.design): offset, layer_stack, directions=None, - vertical=False): + vertical=False, + parent=None): """ The net list is a list of the nets with each net being a list of pins to be connected. The offset is the lower-left of where the @@ -103,6 +104,8 @@ class channel_route(design.design): self.layer_stack = layer_stack self.directions = directions self.vertical = vertical + # For debugging... + self.parent = parent if not directions or directions == "pref": # Use the preferred layer directions @@ -167,7 +170,7 @@ class channel_route(design.design): for net2 in nets: if net1.name == net2.name: continue - if net1.hcg_nets_overlap(net2): + if net1.segment_overlap(net2): try: hcg[net1.name].add(net2.name) except KeyError: @@ -202,7 +205,7 @@ class channel_route(design.design): if net1.name == net2.name: continue - if net1.vcg_nets_overlap(net2, pitch): + if net1.pins_overlap(net2, pitch): vcg[net2.name].add(net1.name) # Check if there are any cycles net1 <---> net2 in the VCG @@ -212,9 +215,9 @@ class channel_route(design.design): # so adjust if this is the case min_value = min([n.min_value for n in nets]) if self.vertical: - real_channel_offset = vector(self.offset.x, min_value) + real_channel_offset = vector(self.offset.x, min(min_value, self.offset.y)) else: - real_channel_offset = vector(min_value, self.offset.y) + real_channel_offset = vector(min(min_value, self.offset.x), self.offset.y) current_offset = real_channel_offset # Sort nets by left edge value @@ -256,7 +259,15 @@ class channel_route(design.design): current_offset_value = current_offset.y if self.vertical else current_offset.x initial_offset_value = real_channel_offset.y if self.vertical else real_channel_offset.x if current_offset_value == initial_offset_value: - # FIXME: We don't support cyclic VCGs right now. + debug.info(0, "Channel offset: {}".format(real_channel_offset)) + debug.info(0, "Current offset: {}".format(current_offset)) + debug.info(0, "VCG {}".format(str(vcg))) + debug.info(0, "HCG {}".format(str(hcg))) + for net in nets: + debug.info(0, "{0} pin: {1}".format(net.name, str(net.pins))) + if self.parent: + debug.info(0, "Saving vcg.gds") + self.parent.gds_write("vcg.gds") debug.error("Cyclic VCG in channel router.", -1) # Increment the track and reset the offset to the start (like a typewriter) From f35848e4f8ea152618ab8b0b6e826c58fed546de Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Jul 2020 12:02:59 -0700 Subject: [PATCH 2/8] Route col flops separately. Flip port 1 col flop for easier routing. --- compiler/sram/sram_1bank.py | 61 ++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 18f3414c..f91b5d2d 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -170,10 +170,10 @@ class sram_1bank(sram_base): x_offset = self.control_logic_insts[port].lx() - 2 * self.dff.width y_offset = self.bank.height + self.data_bus_size[port] + self.dff.height if self.col_addr_dff: - col_addr_pos[port] = vector(x_offset - self.col_addr_dff_insts[port].width, + col_addr_pos[port] = vector(x_offset, y_offset) - self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX") - x_offset = self.col_addr_dff_insts[port].lx() + self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="XY") + x_offset = self.col_addr_dff_insts[port].lx() - self.col_addr_dff_insts[port].width else: col_addr_pos[port] = vector(x_offset, y_offset) @@ -350,13 +350,29 @@ class sram_1bank(sram_base): route_map = [] - # column mux dff + # column mux dff is routed on it's own since it is to the far end + # decoder inputs are min pitch M2, so need to use lower layer stack if self.col_addr_size > 0: dff_names = ["dout_{}".format(x) for x in range(self.col_addr_size)] dff_pins = [self.col_addr_dff_insts[port].get_pin(x) for x in dff_names] bank_names = ["addr{0}_{1}".format(port, x) for x in range(self.col_addr_size)] bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] route_map.extend(list(zip(bank_pins, dff_pins))) + + if port == 0: + offset = vector(self.control_logic_insts[port].rx() + self.dff.width, + - self.data_bus_size[port] + 2 * self.m1_pitch) + else: + offset = vector(0, + self.bank.height + 2 * self.m1_space) + + self.create_horizontal_channel_route(netlist=route_map, + offset=offset, + layer_stack=self.m1_stack) + + + + route_map = [] # wmask dff if self.num_wmasks > 0 and port in self.write_ports: @@ -397,29 +413,24 @@ class sram_1bank(sram_base): else: layer_stack = self.m1_stack - if port == 0: - offset = vector(self.control_logic_insts[port].rx() + self.dff.width, - - self.data_bus_size[port] + 2 * self.m1_pitch) - else: - offset = vector(0, - self.bank.height + 2 * self.m1_space) - if len(route_map) > 0: - self.create_horizontal_channel_route(netlist=route_map, + if port == 0: + offset = vector(self.control_logic_insts[port].rx() + self.dff.width, + - self.data_bus_size[port] + 2 * self.m1_pitch) + import channel_route + cr = channel_route.channel_route(netlist=route_map, offset=offset, - layer_stack=layer_stack) - - # # Route these separately because sometimes the pin pitch on the write driver is too narrow for M3 (FreePDK45) - # # spare wen dff - # if self.num_spare_cols > 0 and port in self.write_ports: - # dff_names = ["dout_{}".format(x) for x in range(self.num_spare_cols)] - # dff_pins = [self.spare_wen_dff_insts[port].get_pin(x) for x in dff_names] - # bank_names = ["bank_spare_wen{0}_{1}".format(port, x) for x in range(self.num_spare_cols)] - # bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] - # route_map = zip(bank_pins, dff_pins) - # self.create_horizontal_channel_route(netlist=route_map, - # offset=offset, - # layer_stack=self.m1_stack) + layer_stack=layer_stack, + parent=self) + self.add_inst("hc", cr) + self.connect_inst([]) + + else: + offset = vector(0, + self.bank.height + 2 * self.m1_space) + self.create_horizontal_channel_route(netlist=route_map, + offset=offset, + layer_stack=layer_stack) def route_clk(self): """ Route the clock network """ From f87b427f760b9e68ff73d4799f502e8b2a9f8884 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Jul 2020 12:03:25 -0700 Subject: [PATCH 3/8] Add parent to channel route for dumpign debug gds. --- compiler/base/hierarchy_layout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 8995488a..22826054 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1018,7 +1018,7 @@ class layout(): Wrapper to create a vertical channel route """ import channel_route - cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=True) + cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=True, parent=self) self.add_inst("vc", cr) self.connect_inst([]) @@ -1027,7 +1027,7 @@ class layout(): Wrapper to create a horizontal channel route """ import channel_route - cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=False) + cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=False, parent=self) self.add_inst("hc", cr) self.connect_inst([]) From 2ccf3aea3b9f48121d98f992a466a0197bfddb22 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Jul 2020 13:25:47 -0700 Subject: [PATCH 4/8] Set channel route height and width (of routes, not pins) --- compiler/base/channel_route.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/compiler/base/channel_route.py b/compiler/base/channel_route.py index 61af303c..00ad6e37 100644 --- a/compiler/base/channel_route.py +++ b/compiler/base/channel_route.py @@ -213,11 +213,12 @@ class channel_route(design.design): # Some of the pins may be to the left/below the channel offset, # so adjust if this is the case - min_value = min([n.min_value for n in nets]) + self.min_value = min([n.min_value for n in nets]) + self.max_value = min([n.max_value for n in nets]) if self.vertical: - real_channel_offset = vector(self.offset.x, min(min_value, self.offset.y)) + real_channel_offset = vector(self.offset.x, min(self.min_value, self.offset.y)) else: - real_channel_offset = vector(min(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 # Sort nets by left edge value @@ -278,14 +279,12 @@ class channel_route(design.design): # Return the size of the channel if self.vertical: - self.width = 0 - self.height = current_offset.y - return current_offset.y + self.vertical_nonpref_pitch - self.offset.y + self.width = current_offset.x + self.horizontal_nonpref_pitch - self.offset.x + self.height = self.max_value + self.vertical_nonpref_pitch - self.offset.y else: - self.width = current_offset.x - self.height = 0 - return current_offset.x + self.horizontal_nonpref_pitch - self.offset.x - + self.width = self.max_value + self.horizontal_nonpref_pitch - self.offset.x + self.height = current_offset.y + self.vertical_nonpref_pitch - self.offset.y + def get_layer_pitch(self, layer): """ Return the track pitch on a given layer """ try: From a36e89e103396a214fc22007c78d653dd674a607 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Jul 2020 13:26:05 -0700 Subject: [PATCH 5/8] Replace data flops depending on channel width --- compiler/sram/sram_1bank.py | 231 ++++++++++++++++++++++-------------- 1 file changed, 139 insertions(+), 92 deletions(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index f91b5d2d..f8c30428 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -10,6 +10,8 @@ from vector import vector from sram_base import sram_base from contact import m2_via from globals import OPTS +import channel_route + class sram_1bank(sram_base): """ @@ -58,12 +60,14 @@ class sram_1bank(sram_base): # the sense amps/column mux and cell array) # The x-coordinate is placed to allow a single clock wire (plus an extra pitch) # up to the row address DFFs. - control_pos = [None] * len(self.all_ports) - row_addr_pos = [None] * len(self.all_ports) - col_addr_pos = [None] * len(self.all_ports) - wmask_pos = [None] * len(self.all_ports) - spare_wen_pos = [None] * len(self.all_ports) - data_pos = [None] * len(self.all_ports) + self.control_pos = [None] * len(self.all_ports) + self.row_addr_pos = [None] * len(self.all_ports) + + # DFFs are placd on their own + self.col_addr_pos = [None] * len(self.all_ports) + self.wmask_pos = [None] * len(self.all_ports) + self.spare_wen_pos = [None] * len(self.all_ports) + self.data_pos = [None] * len(self.all_ports) # These positions utilize the channel route sizes. # FIXME: Auto-compute these rather than manual computation. @@ -75,9 +79,11 @@ class sram_1bank(sram_base): # Spare wen are on a separate layer so not included # Start with 1 track minimum self.data_bus_size = [1] * len(self.all_ports) + self.col_addr_bus_size = [1] * len(self.all_ports) for port in self.all_ports: + # The column address wires are routed separately from the data bus and will always be smaller. # All ports need the col addr flops - self.data_bus_size[port] += self.col_addr_size + self.col_addr_bus_size[port] = self.col_addr_size * self.m4_nonpref_pitch # Write ports need the data input flops and write mask flops if port in self.write_ports: self.data_bus_size[port] += self.num_wmasks + self.word_size @@ -89,119 +95,146 @@ class sram_1bank(sram_base): self.data_bus_size[port] *= self.m4_nonpref_pitch # Add the gap in unit length self.data_bus_size[port] += self.data_bus_gap - - # Port 0 - port = 0 - # This includes 2 M2 pitches for the row addr clock line. - # The delay line is aligned with the bitcell array while the control logic is aligned with the port_data - # using the control_logic_center value. - 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.control_logic_insts[port].place(control_pos[port]) - + # The control and row addr flops are independent of any bus widths. + self.place_control() + self.place_row_addr_dffs() + + # Place with an initial wide channel (from above) + self.place_dffs() + # Route the channel and set to the new data bus size + self.route_dffs(add_routes=False) + # Re-place with the new channel size + self.place_dffs() + # Now route the channel + self.route_dffs() + + def place_row_addr_dffs(self): + """ + Must be run after place control logic. + """ + port = 0 # 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 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]) + self.row_addr_pos[port] = vector(x_offset, y_offset) + self.row_addr_dff_insts[port].place(self.row_addr_pos[port]) + if len(self.all_ports)>1: + port = 1 + # 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 + # 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) + self.row_addr_pos[port] = vector(x_offset, y_offset) + self.row_addr_dff_insts[port].place(self.row_addr_pos[port], mirror="XY") + + def place_control(self): + port = 0 + + # This includes 2 M2 pitches for the row addr clock line. + # The delay line is aligned with the bitcell array while the control logic is aligned with the port_data + # using the control_logic_center value. + self.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.control_logic_insts[port].place(self.control_pos[port]) + if len(self.all_ports) > 1: + port = 1 + # This includes 2 M2 pitches for the row addr clock line + # The delay line is aligned with the bitcell array while the control logic is aligned with the port_data + # using the control_logic_center value. + self.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) + self.control_logic_insts[port].place(self.control_pos[port], mirror="XY") + + def place_dffs(self): + """ + Place the col addr, data, wmask, and spare data DFFs. + This can be run more than once after we recompute the channel width. + """ + + port = 0 # Add the col address flops below the bank to the right of the control logic x_offset = self.control_logic_insts[port].rx() + self.dff.width y_offset = - self.data_bus_size[port] - self.dff.height if self.col_addr_dff: - col_addr_pos[port] = vector(x_offset, - y_offset) - self.col_addr_dff_insts[port].place(col_addr_pos[port]) + self.col_addr_pos[port] = vector(x_offset, + y_offset) + self.col_addr_dff_insts[port].place(self.col_addr_pos[port]) x_offset = self.col_addr_dff_insts[port].rx() else: - col_addr_pos[port] = vector(x_offset, 0) + self.col_addr_pos[port] = vector(x_offset, 0) if port in self.write_ports: if self.write_size: # Add the write mask flops below the write mask AND array. - wmask_pos[port] = vector(x_offset, - y_offset) - self.wmask_dff_insts[port].place(wmask_pos[port]) + self.wmask_pos[port] = vector(x_offset, + y_offset) + self.wmask_dff_insts[port].place(self.wmask_pos[port]) x_offset = self.wmask_dff_insts[port].rx() # Add the data flops below the write mask flops. - data_pos[port] = vector(x_offset, - y_offset) - self.data_dff_insts[port].place(data_pos[port]) + self.data_pos[port] = vector(x_offset, + y_offset) + self.data_dff_insts[port].place(self.data_pos[port]) x_offset = self.data_dff_insts[port].rx() # Add spare write enable flops to the right of data flops since the spare columns # will be on the right if self.num_spare_cols: - spare_wen_pos[port] = vector(x_offset, - y_offset) - self.spare_wen_dff_insts[port].place(spare_wen_pos[port]) + self.spare_wen_pos[port] = vector(x_offset, + y_offset) + self.spare_wen_dff_insts[port].place(self.spare_wen_pos[port]) x_offset = self.spare_wen_dff_insts[port].rx() else: - wmask_pos[port] = vector(x_offset, y_offset) - data_pos[port] = vector(x_offset, y_offset) - spare_wen_pos[port] = vector(x_offset, y_offset) + self.wmask_pos[port] = vector(x_offset, y_offset) + self.data_pos[port] = vector(x_offset, y_offset) + self.spare_wen_pos[port] = vector(x_offset, y_offset) - if len(self.all_ports)>1: - # Port 1 + if len(self.all_ports) > 1: port = 1 - - # This includes 2 M2 pitches for the row addr clock line - # The delay line is aligned with the bitcell array while the control logic is aligned with the port_data - # using the control_logic_center value. - 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) - 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 col address flops below the bank to the right of the control logic x_offset = self.control_logic_insts[port].lx() - 2 * self.dff.width y_offset = self.bank.height + self.data_bus_size[port] + self.dff.height if self.col_addr_dff: - col_addr_pos[port] = vector(x_offset, - y_offset) - self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="XY") + self.col_addr_pos[port] = vector(x_offset, + y_offset) + self.col_addr_dff_insts[port].place(self.col_addr_pos[port], mirror="XY") x_offset = self.col_addr_dff_insts[port].lx() - self.col_addr_dff_insts[port].width else: - col_addr_pos[port] = vector(x_offset, y_offset) + self.col_addr_pos[port] = vector(x_offset, y_offset) if port in self.write_ports: # Add spare write enable flops to the right of the data flops since the spare # columns will be on the left if self.num_spare_cols: - spare_wen_pos[port] = vector(x_offset - self.spare_wen_dff_insts[port].width, - y_offset) - self.spare_wen_dff_insts[port].place(spare_wen_pos[port], mirror="MX") + self.spare_wen_pos[port] = vector(x_offset - self.spare_wen_dff_insts[port].width, + y_offset) + self.spare_wen_dff_insts[port].place(self.spare_wen_pos[port], mirror="MX") x_offset = self.spare_wen_dff_insts[port].lx() if self.write_size: # Add the write mask flops below the write mask AND array. - wmask_pos[port] = vector(x_offset - self.wmask_dff_insts[port].width, - y_offset) - self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX") + self.wmask_pos[port] = vector(x_offset - self.wmask_dff_insts[port].width, + y_offset) + self.wmask_dff_insts[port].place(self.wmask_pos[port], mirror="MX") x_offset = self.wmask_dff_insts[port].lx() # Add the data flops below the write mask flops. - data_pos[port] = vector(x_offset - self.data_dff_insts[port].width, - y_offset) - self.data_dff_insts[port].place(data_pos[port], mirror="MX") + self.data_pos[port] = vector(x_offset - self.data_dff_insts[port].width, + y_offset) + self.data_dff_insts[port].place(self.data_pos[port], mirror="MX") else: - wmask_pos[port] = vector(x_offset, y_offset) - data_pos[port] = vector(x_offset, y_offset) - spare_wen_pos[port] = vector(x_offset, y_offset) - + self.wmask_pos[port] = vector(x_offset, y_offset) + self.data_pos[port] = vector(x_offset, y_offset) + self.spare_wen_pos[port] = vector(x_offset, y_offset) + def add_layout_pins(self): """ Add the top-level pins for a single bank SRAM with control. @@ -343,10 +376,12 @@ class sram_1bank(sram_base): self.route_row_addr_dff() + def route_dffs(self, add_routes=True): + for port in self.all_ports: - self.route_dff(port) + self.route_dff(port, add_routes) - def route_dff(self, port): + def route_dff(self, port, add_routes): route_map = [] @@ -366,12 +401,16 @@ class sram_1bank(sram_base): offset = vector(0, self.bank.height + 2 * self.m1_space) - self.create_horizontal_channel_route(netlist=route_map, - offset=offset, - layer_stack=self.m1_stack) - + cr = channel_route.channel_route(netlist=route_map, + offset=offset, + layer_stack=self.m1_stack, + parent=self) + if add_routes: + self.add_inst("hc", cr) + self.connect_inst([]) + else: + self.col_addr_bus_size[port] = cr.height - route_map = [] # wmask dff @@ -407,31 +446,39 @@ class sram_1bank(sram_base): bank_names = ["bank_spare_wen{0}_{1}".format(port, x) for x in range(self.num_spare_cols)] bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] route_map.extend(list(zip(bank_pins, dff_pins))) - - if self.num_wmasks > 0 and port in self.write_ports: - layer_stack = self.m3_stack - else: - layer_stack = self.m1_stack if len(route_map) > 0: + + if self.num_wmasks > 0 and port in self.write_ports: + layer_stack = self.m3_stack + else: + layer_stack = self.m1_stack + if port == 0: offset = vector(self.control_logic_insts[port].rx() + self.dff.width, - self.data_bus_size[port] + 2 * self.m1_pitch) - import channel_route cr = channel_route.channel_route(netlist=route_map, offset=offset, layer_stack=layer_stack, parent=self) - self.add_inst("hc", cr) - self.connect_inst([]) - + if add_routes: + self.add_inst("hc", cr) + self.connect_inst([]) + else: + self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) else: offset = vector(0, self.bank.height + 2 * self.m1_space) - self.create_horizontal_channel_route(netlist=route_map, - offset=offset, - layer_stack=layer_stack) - + cr = channel_route.channel_route(netlist=route_map, + offset=offset, + layer_stack=layer_stack, + parent=self) + if add_routes: + self.add_inst("hc", cr) + self.connect_inst([]) + else: + self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + def route_clk(self): """ Route the clock network """ From 82bbacdfb57b100a2fac521525a390a667ff2598 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Jul 2020 13:43:57 -0700 Subject: [PATCH 6/8] Add data bus gap to dynamically computed channel width --- compiler/sram/sram_1bank.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index f8c30428..2808c8ca 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -465,7 +465,7 @@ class sram_1bank(sram_base): self.add_inst("hc", cr) self.connect_inst([]) else: - self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap else: offset = vector(0, self.bank.height + 2 * self.m1_space) @@ -477,7 +477,7 @@ class sram_1bank(sram_base): self.add_inst("hc", cr) self.connect_inst([]) else: - self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap def route_clk(self): """ Route the clock network """ From 0ed81aa923fcd0e7b717616318c684fa8b9071d3 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Jul 2020 14:11:52 -0700 Subject: [PATCH 7/8] Removed extraneous shift from added mirroring --- compiler/sram/sram_1bank.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 2808c8ca..6b334060 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -206,7 +206,7 @@ class sram_1bank(sram_base): self.col_addr_pos[port] = vector(x_offset, y_offset) self.col_addr_dff_insts[port].place(self.col_addr_pos[port], mirror="XY") - x_offset = self.col_addr_dff_insts[port].lx() - self.col_addr_dff_insts[port].width + x_offset = self.col_addr_dff_insts[port].lx() else: self.col_addr_pos[port] = vector(x_offset, y_offset) From 58846a4a25eed59b4e8bd84d1f69da80331cb5c0 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Jul 2020 17:57:38 -0700 Subject: [PATCH 8/8] Limit wordline driver size. Place row addr dff near predecoders. --- compiler/modules/bank.py | 3 ++- compiler/modules/hierarchical_decoder.py | 21 ++++++++++----------- compiler/modules/port_address.py | 2 ++ compiler/sram/sram_1bank.py | 6 +++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 158ac37b..b0707edb 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -211,10 +211,11 @@ class bank(design.design): self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width, 0) # UPPER LEFT QUADRANT - # To the left of the bitcell array + # To the left of the bitcell array above the predecoders and control logic x_offset = self.m2_gap + self.port_address.width self.port_address_offsets[port] = vector(-x_offset, self.main_bitcell_array_bottom) + self.predecoder_height = self.port_address.predecoder_height + self.port_address_offsets[port].y # LOWER LEFT QUADRANT # Place the col decoder left aligned with wordline driver diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 3233bdc8..dbacd051 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -314,24 +314,23 @@ class hierarchical_decoder(design.design): for i in range(self.no_of_pre3x8): self.place_pre3x8(i) + self.predecode_height = 0 + if self.no_of_pre2x4 > 0: + self.predecode_height = self.pre2x4_inst[-1].uy() + if self.no_of_pre3x8 > 0: + self.predecode_height = self.pre3x8_inst[-1].uy() + def place_pre2x4(self, num): """ Place 2x4 predecoder to the left of the origin """ - if (self.num_inputs == 2): - base = vector(-self.pre2_4.width, 0) - else: - base= vector(-self.pre2_4.width, num * (self.pre2_4.height + self.predecoder_spacing)) - + base= vector(-self.pre2_4.width, num * (self.pre2_4.height + self.predecoder_spacing)) self.pre2x4_inst[num].place(base) def place_pre3x8(self, num): """ Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """ - if (self.num_inputs == 3): - offset = vector(-self.pre_3_8.width, 0) - else: - height = self.no_of_pre2x4 * (self.pre2_4.height + self.predecoder_spacing) + num * (self.pre3_8.height + self.predecoder_spacing) - offset = vector(-self.pre3_8.width, height) - + height = self.no_of_pre2x4 * (self.pre2_4.height + self.predecoder_spacing) \ + + num * (self.pre3_8.height + self.predecoder_spacing) + offset = vector(-self.pre3_8.width, height) self.pre3x8_inst[num].place(offset) def create_row_decoder(self): diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index a73e536c..980c9d96 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -153,6 +153,8 @@ class port_address(design.design): wordline_driver_offset = vector(self.row_decoder.width, 0) self.wordline_driver_inst.place(wordline_driver_offset) self.row_decoder_inst.place(row_decoder_offset) + # Pass this up + self.predecoder_height = self.row_decoder.predecoder_height self.height = self.row_decoder.height self.width = self.wordline_driver_inst.rx() diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 6b334060..a5dfb0e5 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -117,7 +117,7 @@ class sram_1bank(sram_base): # 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 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) + y_offset = max(self.control_logic_insts[port].uy(), self.bank.predecoder_height) self.row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_dff_insts[port].place(self.row_addr_pos[port]) @@ -125,8 +125,8 @@ class sram_1bank(sram_base): port = 1 # 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 - # 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) + # If it can be placed above the predecoder and below the control logic, do it + y_offset = self.bank.bank_array_ll.y self.row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_dff_insts[port].place(self.row_addr_pos[port], mirror="XY")