From 32576fb62c9ac7a69518f7fe1714eeb1de42d912 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Apr 2020 13:27:50 -0700 Subject: [PATCH] Convert wordline driver to pand2 rather than pnand2+pdriver --- compiler/modules/control_logic.py | 2 +- compiler/modules/hierarchical_decoder.py | 1 - compiler/modules/wordline_driver.py | 119 ++++++++++------------- compiler/pgates/pand2.py | 3 +- 4 files changed, 54 insertions(+), 71 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index b4c7402e..5dd8182e 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -90,7 +90,7 @@ class control_logic(design.design): self.add_mod(self.ctrl_dff_array) self.and2 = factory.create(module_type="pand2", - size=4, + size=12, height=dff_height) self.add_mod(self.and2) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index f46849c6..69822149 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -32,7 +32,6 @@ class hierarchical_decoder(design.design): self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple except AttributeError: self.cell_multiple = 1 - # For debugging self.cell_height = self.cell_multiple * b.height self.num_outputs = num_outputs diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index d84457ba..76a31074 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -7,10 +7,12 @@ # import debug import design +import math import contact from vector import vector from sram_factory import factory from globals import OPTS +from tech import cell_properties class wordline_driver(design.design): @@ -26,6 +28,13 @@ class wordline_driver(design.design): self.rows = rows self.cols = cols + + b = factory.create(module_type="bitcell") + try: + self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple + except AttributeError: + self.cell_multiple = 1 + self.cell_height = self.cell_multiple * b.height self.create_netlist() if not OPTS.netlist_only: @@ -37,6 +46,7 @@ class wordline_driver(design.design): self.create_drivers() def create_layout(self): + self.setup_layout_constants() self.place_drivers() self.route_layout() self.route_vdd_gnd() @@ -56,17 +66,10 @@ class wordline_driver(design.design): self.add_pin("gnd", "GROUND") def add_modules(self): - b = factory.create(module_type="bitcell") - - self.inv = factory.create(module_type="pdriver", - fanout=self.cols, - neg_polarity=True, - height=b.height) - self.add_mod(self.inv) - - self.nand2 = factory.create(module_type="pnand2", - height=b.height) - self.add_mod(self.nand2) + self.and2 = factory.create(module_type="pand2", + height=self.cell_height, + size=self.cols) + self.add_mod(self.and2) def route_vdd_gnd(self): """ @@ -75,68 +78,64 @@ class wordline_driver(design.design): """ # Find the x offsets for where the vias/pins should be placed - a_xoffset = self.nand_inst[0].lx() + xoffset_list = [self.and_inst[0].lx()] for num in range(self.rows): # this will result in duplicate polygons for rails, but who cares - # use the inverter offset even though it will be the nand's too + # use the inverter offset even though it will be the and's too (gate_offset, y_dir) = self.get_gate_offset(0, - self.inv.height, + self.and2.height, num) - # Route both supplies for name in ["vdd", "gnd"]: - supply_pin = self.inv2_inst[num].get_pin(name) + supply_pin = self.and_inst[num].get_pin(name) # Add pins in two locations - for xoffset in [a_xoffset]: + for xoffset in xoffset_list: pin_pos = vector(xoffset, supply_pin.cy()) self.add_power_pin(name, pin_pos) def create_drivers(self): - self.nand_inst = [] - self.inv2_inst = [] + self.and_inst = [] for row in range(self.rows): - name_nand = "wl_driver_nand{}".format(row) - name_inv2 = "wl_driver_inv{}".format(row) + name_and = "wl_driver_and{}".format(row) - # add nand 2 - self.nand_inst.append(self.add_inst(name=name_nand, - mod=self.nand2)) + # add and2 + self.and_inst.append(self.add_inst(name=name_and, + mod=self.and2)) self.connect_inst(["en", "in_{0}".format(row), - "wl_bar_{0}".format(row), - "vdd", "gnd"]) - # add inv2 - self.inv2_inst.append(self.add_inst(name=name_inv2, - mod=self.inv)) - self.connect_inst(["wl_bar_{0}".format(row), "wl_{0}".format(row), "vdd", "gnd"]) + + def setup_layout_constants(self): + # We may have more than one bitcell per decoder row + self.num_rows = math.ceil(self.rows / self.cell_multiple) + # We will place this many final decoders per row + self.decoders_per_row = math.ceil(self.rows / self.num_rows) def place_drivers(self): - nand2_xoffset = 2 * self.m1_width + 5 * self.m1_space - inv2_xoffset = nand2_xoffset + self.nand2.width + and2_xoffset = 2 * self.m1_width + 5 * self.m1_space - self.width = inv2_xoffset + self.inv.width - self.height = self.inv.height * self.rows + self.width = and2_xoffset + self.and2.width + self.height = self.and2.height * self.num_rows for row in range(self.rows): + #row = math.floor(inst_index / self.decoders_per_row) + #dec = inst_index % self.decoders_per_row + if (row % 2): - y_offset = self.inv.height * (row + 1) + y_offset = self.and2.height * (row + 1) inst_mirror = "MX" else: - y_offset = self.inv.height * row + y_offset = self.and2.height * row inst_mirror = "R0" - nand2_offset = [nand2_xoffset, y_offset] - inv2_offset = [inv2_xoffset, y_offset] + # x_off = self.internal_routing_width + dec * and_mod.width + and2_offset = [and2_xoffset, y_offset] - # add nand 2 - self.nand_inst[row].place(offset=nand2_offset, - mirror=inst_mirror) - # add inv2 - self.inv2_inst[row].place(offset=inv2_offset, + # add and2 + self.and_inst[row].place(offset=and2_offset, mirror=inst_mirror) def route_layout(self): @@ -151,11 +150,10 @@ class wordline_driver(design.design): height=self.height) for row in range(self.rows): - nand_inst = self.nand_inst[row] - inv2_inst = self.inv2_inst[row] + and_inst = self.and_inst[row] # en connection - a_pin = nand_inst.get_pin("A") + a_pin = and_inst.get_pin("A") a_pos = a_pin.lc() clk_offset = vector(en_pin.bc().x, a_pos.y) self.add_segment_center(layer="m1", @@ -164,18 +162,10 @@ class wordline_driver(design.design): self.add_via_center(layers=self.m1_stack, offset=clk_offset) - # Nand2 out to 2nd inv - zr_pos = nand_inst.get_pin("Z").rc() - al_pos = inv2_inst.get_pin("A").lc() - # ensure the bend is in the middle - mid1_pos = vector(0.5 * (zr_pos.x + al_pos.x), zr_pos.y) - mid2_pos = vector(0.5 * (zr_pos.x + al_pos.x), al_pos.y) - self.add_path("m1", [zr_pos, mid1_pos, mid2_pos, al_pos]) - - # connect the decoder input pin to nand2 B - b_pin = nand_inst.get_pin("B") + # connect the decoder input pin to and2 B + b_pin = and_inst.get_pin("B") b_pos = b_pin.lc() - # needs to move down since B nand input is + # needs to move down since B and input is # nearly aligned with A inv input up_or_down = self.m2_space if row % 2 else -self.m2_space input_offset = vector(0, b_pos.y + up_or_down) @@ -192,7 +182,7 @@ class wordline_driver(design.design): offset=mid_via_offset, directions=("V", "V")) - # now connect to the nand2 B + # now connect to the and2 B self.add_path("m2", [mid_via_offset, b_pos]) contact_offset = b_pos - vector(0.5 * contact.m1_via.height, 0) self.add_via_center(layers=self.m1_stack, @@ -200,7 +190,7 @@ class wordline_driver(design.design): directions=("H", "H")) # output each WL on the right - wl_offset = inv2_inst.get_pin("Z").rc() + wl_offset = and_inst.get_pin("Z").rc() self.add_layout_pin_segment_center(text="wl_{0}".format(row), layer="m1", start=wl_offset, @@ -213,13 +203,8 @@ class wordline_driver(design.design): """ stage_effort_list = [] - stage1_cout = self.inv.get_cin() - stage1 = self.nand2.get_stage_effort(stage1_cout, inp_is_rise) + stage1 = self.and2.get_stage_effort(external_cout, inp_is_rise) stage_effort_list.append(stage1) - last_stage_is_rise = stage1.is_rise - - stage2 = self.inv.get_stage_efforts(external_cout, last_stage_is_rise) - stage_effort_list.extend(stage2) return stage_effort_list @@ -228,6 +213,6 @@ class wordline_driver(design.design): Get the relative capacitance of all the enable connections in the bank """ - # The enable is connected to a nand2 for every row. - total_cin = self.nand2.get_cin() * self.rows + # The enable is connected to a and2 for every row. + total_cin = self.and2.get_cin() * self.rows return total_cin diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 995296b6..4c044f1c 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -30,13 +30,12 @@ class pand2(pgate.pgate): self.create_insts() def create_modules(self): - # Shield the cap, but have at least a stage effort of 4 self.nand = factory.create(module_type="pnand2", height=self.height) self.add_mod(self.nand) self.inv = factory.create(module_type="pdriver", neg_polarity=True, - fanout=3*self.size, + fanout=self.size, height=self.height) self.add_mod(self.inv)