From a2422cc8d4bc1f74ba42f62763f4b720861b3737 Mon Sep 17 00:00:00 2001 From: Matthew Guthaus Date: Wed, 6 Nov 2019 21:51:21 +0000 Subject: [PATCH] Sometimes round down pdriver to fix polarity --- compiler/modules/wordline_driver.py | 12 +++---- compiler/pgates/pdriver.py | 53 +++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index a0a92b35..fbd800b2 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -65,9 +65,9 @@ class wordline_driver(design.design): self.add_mod(self.nand2) def route_vdd_gnd(self): - """ - Add a pin for each row of vdd/gnd which - are must-connects next level up. + """ + Add a pin for each row of vdd/gnd which + are must-connects next level up. """ # Find the x offsets for where the vias/pins should be placed @@ -91,8 +91,8 @@ class wordline_driver(design.design): self.add_power_pin(name, pin_pos) def create_drivers(self): - self.nand_inst = [] - self.inv2_inst = [] + self.nand_inst = [] + self.inv2_inst = [] for row in range(self.rows): name_nand = "wl_driver_nand{}".format(row) name_inv2 = "wl_driver_inv{}".format(row) @@ -164,7 +164,7 @@ class wordline_driver(design.design): # 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 + # 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("metal1", [zr_pos, mid1_pos, mid2_pos, al_pos]) diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index bb7739b7..2e778220 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -27,12 +27,12 @@ class pdriver(pgate.pgate): self.size_list = size_list self.fanout = fanout - if not size_list and self.fanout == 0: - debug.error("Either fanout or size list must be specified.", -1) - if self.size_list and self.fanout != 0: - debug.error("Cannot specify both size_list and fanout.", -1) - if self.size_list and self.neg_polarity: - debug.error("Cannot specify both size_list and neg_polarity.", -1) + debug.check(self.size_list or self.fanout > 0, + "Either fanout or size list must be specified.") + debug.check(not (self.size_list and self.fanout > 0), + "Cannot specify both size_list and fanout.") + debug.check(not (self.size_list and self.neg_polarity), + "Cannot specify both size_list and neg_polarity.") # Creates the netlist and layout pgate.pgate.__init__(self, name, height) @@ -43,21 +43,44 @@ class pdriver(pgate.pgate): self.num_stages = len(self.size_list) else: # Find the optimal number of stages for the given effort - self.num_stages = max(1, - int(round(self.fanout ** (1 / self.stage_effort)))) + optimal_stages = self.fanout ** (1 / self.stage_effort) + rounded_stages = int(round(optimal_stages)) + difference = optimal_stages - rounded_stages - # Increase the number of stages if we need to fix polarity - if self.neg_polarity and (self.num_stages % 2 == 0): - self.num_stages += 1 - elif not self.neg_polarity and (self.num_stages % 2): - self.num_stages += 1 + + # Determine if we need to fix the polarity + if self.neg_polarity and (rounded_stages % 2 == 0): + wrong_polarity = True + elif not self.neg_polarity and (optimal_stages % 2): + wrong_polarity = True + else: + wrong_polarity = False + + # Depending on the difference, round up or down. + if wrong_polarity: + # If we rounded up and can round down, do it. + if difference < 0 and rounded_stages > 1: + rounded_stages -= 1 + else: + # Otherwise, we must round up + rounded_stages += 1 + + if self.neg_polarity: + # Need at least one stage for negative + self.num_stages = max(1, rounded_stages) + else: + # Need at least two stages for positive + self.num_stages = max(2, rounded_stages) + # Use the actual stage effort + actual_stage_effort = self.fanout / self.num_stages + self.size_list = [] # compute sizes backwards from the fanout fanout_prev = self.fanout for x in range(self.num_stages): - fanout_prev = max(round(fanout_prev / self.stage_effort), 1) - self.size_list.append(fanout_prev) + fanout_prev = fanout_prev / actual_stage_effort + self.size_list.append(max(round(fanout_prev), 1)) # reverse the sizes to be from input to output self.size_list.reverse()