diff --git a/compiler/hierarchical_predecode.py b/compiler/hierarchical_predecode.py index ef5095af..3675828f 100644 --- a/compiler/hierarchical_predecode.py +++ b/compiler/hierarchical_predecode.py @@ -3,8 +3,6 @@ import design import math from tech import drc from contact import contact -from nand_2 import nand_2 -from nand_3 import nand_3 from pinv import pinv from vector import vector from globals import OPTS @@ -41,14 +39,8 @@ class hierarchical_predecode(design.design): beta=2, height=self.bitcell_height) self.add_mod(self.inv) - if self.number_of_inputs ==2: - self.nand = nand_2(name="a_nand_2", - nmos_width=self.nmos_width, - height=self.bitcell_height) - elif self.number_of_inputs ==3: - self.nand = nand_3(name="a_nand_3", - nmos_width=self.nmos_width, - height=self.bitcell_height) + # create_nand redefine in sub class based on number of inputs + self.create_nand() self.add_mod(self.nand) def set_up_constrain(self): @@ -75,12 +67,8 @@ class hierarchical_predecode(design.design): self.gap_between_rail_offset = self.gap_between_rails + drc["minwidth_metal2"] self.rails_x_offset = [] - if self.number_of_inputs == 2: - self.rail_height = (self.number_of_outputs * self.nand.height - - (self.number_of_outputs - 1) * drc["minwidth_metal2"]) - elif self.number_of_inputs == 3: - self.rail_height = (self.number_of_outputs * self.nand.height - - 1.5 * drc["minwidth_metal2"]) + # set_rail_height redefine in sub class + self.set_rail_height() # Creating the left hand side metal2 rails for input connections for hrail_1 in range(self.number_of_inputs): xoffset_1 = (self.metal2_extend_contact @@ -100,10 +88,7 @@ class hierarchical_predecode(design.design): def update_size(self): self.width = self.x_off_inv_2 + self.inv.width - if self.number_of_inputs ==2: - self.height = 4 * self.nand.height - elif self.number_of_inputs ==3: - self.height = 8 * self.nand.height + self.set_height() self.size = vector(self.width, self.height) correct =vector(0, 0.5 * drc["minwidth_metal1"]) self.vdd_position = self.size - correct - vector(0, self.inv.height) @@ -142,10 +127,8 @@ class hierarchical_predecode(design.design): def add_nand(self,connections): for nand_input in range(self.number_of_outputs): - if self.number_of_inputs ==2: - name = "Xpre2x4_nand[{0}]".format(nand_input) - elif self.number_of_inputs ==3: - name = "Xpre3x8_nand[{0}]".format(nand_input) + inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs) + name = "Xpre"+inout+"_nand[{0}]".format(nand_input) if (nand_input % 2 == 0): y_off = nand_input * (self.nand.height) mirror = "R0" @@ -167,30 +150,135 @@ class hierarchical_predecode(design.design): self.connect_inst(connections[nand_input]) def route(self): - # route sub funtions need to be redfined in sub class self.route_input_inverters() self.route_nand_to_rails() self.route_vdd_gnd_from_rails_to_gates() - def route_input_inverters_input(self,inv_rout,inv_in_offset): + def route_input_inverters(self): + # All conections of the inputs inverters [Inputs, outputs, vdd, gnd] + output_shift = self.set_output_shift() + for inv_rout in range(self.number_of_inputs): + setup = self.setup_route_input_inverter(inv_rout,output_shift) + y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup + #add output + correct = y_dir * (output_shift + drc["minwidth_metal1"]) + output_metal = self.cal_input_inverters_output(setup,output_shift,inv_rout) + offset1,offset2=output_metal[0] + offset3,offset4=output_metal[1] + self.add_rect(layer="metal1", + offset=offset1, + width=drc["minwidth_metal1"], + height=offset2.y - offset1.y) + self.add_rect(layer="metal1", + offset=offset3, + width=offset4.x - offset3.x, + height=drc["minwidth_metal1"]) + off_via = [self.rails_x_offset[inv_rout + self.number_of_inputs+2] + self.gap_between_rails, + inv_vdd_offset.y- self.via_shift - correct] + self.add_via(layers = ("metal1", "via1", "metal2"), + offset=off_via, + rotate=90) + #route input + self.add_rect(layer="metal1", + offset=[self.rails_x_offset[inv_rout], + inv_in_offset.y], + width=inv_in_offset.x - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"], + height=drc["minwidth_metal1"]) + self.add_via(layers=("metal1", "via1", "metal2"), + offset=[self.rails_x_offset[inv_rout] + self.gap_between_rails, + inv_in_offset.y - self.via_shift], + rotate=90) + # route vdd + self.add_rect(layer="metal1", + offset=inv_vdd_offset, + width=self.rails_x_offset[self.number_of_inputs] - inv_vdd_offset.x + drc["minwidth_metal2"], + height=drc["minwidth_metal1"]) + # route gnd + self.add_rect(layer="metal1", + offset=inv_gnd_offset, + width=self.rails_x_offset[self.number_of_inputs+1] - inv_gnd_offset.x + drc["minwidth_metal2"], + height=drc["minwidth_metal1"]) + + def setup_route_input_inverter(self, inv_rout, output_shift): + # add Inputs, vdd, gnd of the inputs inverters + if (inv_rout % 2 == 0): + base_offset=[self.x_off_inv_1, inv_rout * self.inv.height ] + y_dir = 1 + else: + base_offset=[self.x_off_inv_1, 2 * self.inv.height - drc["minwidth_metal1"]] + y_dir = -1 + inv_out_offset = base_offset+self.inv.Z_position.scale(1,y_dir) + inv_in_offset = base_offset+self.inv.A_position.scale(1,y_dir) + inv_vdd_offset = base_offset+self.inv.vdd_position.scale(1,y_dir) + inv_gnd_offset = base_offset+self.inv.gnd_position.scale(1,y_dir) + #return info to create output of the input inverter + return [y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset] + + def route_nand_to_rails(self): + # This 2D array defines the connection mapping + nand_input_line_combination = self.get_nand_input_line_combination() + for k in range(self.number_of_outputs): + # create x offset list + index_lst= nand_input_line_combination[k] + line_x_offset = [] + for index in index_lst: + line_x_offset.append(self.rails_x_offset[index]) + # create y offset list + yoffset_nand_in, correct= self.create_y_offsets(k) + # connect based on the two list + for i in range(self.number_of_inputs): + x_offset = line_x_offset[i] + y_offset = yoffset_nand_in[i] + # Connecting the i-th input of Nand3 gate + self.add_rect(layer="metal1", + offset=[x_offset, y_offset], + width=self.x_off_nand - x_offset, + height=drc["minwidth_metal1"]) + self.add_via(layers=("metal1", "via1", "metal2"), + offset=[x_offset+ self.gap_between_rails, + y_offset - self.via_shift - correct[i]], + rotate=90) + # Extended of the top NAND2 to the left hand side input rails + if(k == self.number_of_outputs - 1): + x_offset = self.rails_x_offset[i] + self.add_rect(layer="metal1", + offset=[x_offset, y_offset], + width=self.x_off_nand - x_offset, + height=drc["minwidth_metal1"]) + self.add_via(layers = ("metal1", "via1", "metal2"), + offset=[x_offset + self.gap_between_rails, + y_offset - self.via_shift], + rotate=90) + + def route_vdd_gnd_from_rails_to_gates(self): + via_correct = self.get_via_correct() + for k in range(self.number_of_outputs): + power_line_index = self.number_of_inputs + 1 - (k%2) + yoffset = k * self.inv.height - 0.5 * drc["minwidth_metal1"] + self.add_rect(layer="metal1", + offset=[self.rails_x_offset[power_line_index], + yoffset], + width=self.x_off_nand - self.rails_x_offset[power_line_index], + height=drc["minwidth_metal1"]) + self.add_via(layers = ("metal1", "via1", "metal2"), + offset=[self.rails_x_offset[power_line_index] + self.gap_between_rails, + yoffset - via_correct.y], + rotate=90) + + yoffset = (self.number_of_outputs * self.inv.height + - 0.5 * drc["minwidth_metal1"]) + v_metal = self.get_vertical_metal() + via_y = self.get_via_y() + index = self.number_of_inputs + 1 self.add_rect(layer="metal1", - offset=[self.rails_x_offset[inv_rout], - inv_in_offset.y], - width=inv_in_offset.x - self.rails_x_offset[inv_rout] + drc["minwidth_metal2"], + offset=[self.rails_x_offset[index], yoffset], + width=self.x_off_nand - self.rails_x_offset[index], height=drc["minwidth_metal1"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[self.rails_x_offset[inv_rout] + self.gap_between_rails, - inv_in_offset.y - self.via_shift], + self.add_rect(layer=v_metal, + offset=[self.rails_x_offset[index], self.rail_height], + width=drc["minwidth_"+v_metal], + height=yoffset - self.rail_height) + self.add_via(layers = ("metal1", "via1", "metal2"), + offset=[self.rails_x_offset[index] + self.gap_between_rails, + via_y] - via_correct, rotate=90) - - def route_input_inverters_vdd(self,inv_vdd_offset): - self.add_rect(layer="metal1", - offset=inv_vdd_offset, - width=self.rails_x_offset[self.number_of_inputs] - inv_vdd_offset.x + drc["minwidth_metal2"], - height=drc["minwidth_metal1"]) - - def route_input_inverters_gnd(self,inv_gnd_offset): - self.add_rect(layer="metal1", - offset=inv_gnd_offset, - width=self.rails_x_offset[self.number_of_inputs+1] - inv_gnd_offset.x + drc["minwidth_metal2"], - height=drc["minwidth_metal1"]) diff --git a/compiler/hierarchical_predecode2x4.py b/compiler/hierarchical_predecode2x4.py index c5cfd5b4..411a5c95 100644 --- a/compiler/hierarchical_predecode2x4.py +++ b/compiler/hierarchical_predecode2x4.py @@ -1,6 +1,7 @@ from tech import drc import debug import design +from nand_2 import nand_2 from vector import vector from hierarchical_predecode import hierarchical_predecode @@ -8,7 +9,6 @@ class hierarchical_predecode2x4(hierarchical_predecode): """ Pre 2x4 decoder used in hierarchical_decoder. """ - def __init__(self, nmos_width, cellname): hierarchical_predecode.__init__(self, nmos_width, cellname, 2) @@ -18,6 +18,15 @@ class hierarchical_predecode2x4(hierarchical_predecode): self.create_layout() self.route() + def create_nand(self): + self.nand = nand_2(name="a_nand_2", + nmos_width=self.nmos_width, + height=self.bitcell_height) + + def set_rail_height(self): + self.rail_height = (self.number_of_outputs * self.nand.height + - (self.number_of_outputs - 1) * drc["minwidth_metal2"]) + def create_layout(self): self.create_rails() self.add_inv2x4() @@ -28,6 +37,9 @@ class hierarchical_predecode2x4(hierarchical_predecode): ["B[0]", "B[1]", "Z[0]", "vdd", "gnd"]] self.add_nand(connections) + def set_height(self): + self.height = 4 * self.nand.height + def add_inv2x4(self): self.A_positions = [] for inv_2x4 in range(self.number_of_inputs): @@ -51,109 +63,48 @@ class hierarchical_predecode2x4(hierarchical_predecode): "B[{0}]".format(inv_2x4), "vdd", "gnd"]) - def route_input_inverters(self): - # All conections of the inputs inverters [Inputs, outputs, vdd, gnd] - output_shift = 2 * drc["minwidth_metal1"] - for inv_rout in range(self.number_of_inputs): - if (inv_rout % 2 == 0): - y_dir= 1 - else: - y_dir= -1 - base = vector(self.x_off_inv_1, - (1-y_dir) * (self.inv.height - 0.5 * drc["minwidth_metal1"])) - inv_out_offset = base + self.inv.Z_position.scale(1,y_dir) - inv_in_offset = base + self.inv.A_position.scale(1,y_dir) - inv_vdd_offset = base + self.inv.vdd_position.scale(1,y_dir) - inv_gnd_offset = base + self.inv.gnd_position.scale(1,y_dir) - out_y_mirrored = inv_vdd_offset.y+ output_shift + drc["minwidth_metal1"] - out_offset = [inv_out_offset.x, - inv_out_offset.y* (1 + y_dir) / 2 - + out_y_mirrored * (1 - y_dir) / 2] - # output connection - correct = y_dir * (output_shift + drc["minwidth_metal1"]) - off_via = [self.rails_x_offset[inv_rout + 4] + self.gap_between_rails, - inv_vdd_offset.y- self.via_shift - correct] - self.add_rect(layer="metal1", - offset=out_offset, - width=drc["minwidth_metal1"], - height=(inv_vdd_offset.y- inv_out_offset.y) * y_dir - output_shift) - self.add_rect(layer="metal1", - offset=[inv_out_offset.x, - inv_vdd_offset.y- correct], - width=self.rails_x_offset[inv_rout + 4] - inv_out_offset.x+ drc["minwidth_metal2"], - height=drc["minwidth_metal1"]) - self.add_via(layers = ("metal1", "via1", "metal2"), - offset=off_via, - rotate=90) - self.route_input_inverters_input(inv_rout,inv_in_offset) - self.route_input_inverters_vdd(inv_vdd_offset) - self.route_input_inverters_gnd(inv_gnd_offset) + def cal_input_inverters_output(self,setup,output_shift,inv_rout): + y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup + correct = y_dir * (output_shift + drc["minwidth_metal1"]) + out_offset = vector(inv_out_offset) + if y_dir == -1: + out_offset.y = inv_vdd_offset.y + output_shift + drc["minwidth_metal1"] - def route_nand_to_rails(self): - # This 2D array defines the connection mapping - nand2_input_line_combination = [[4, 5], [6, 5], [4, 7], [6, 7]] - for k in range(self.number_of_outputs): - # create x offset list - x_index = nand2_input_line_combination[k] - line_x_offset = [self.rails_x_offset[x_index[0]], - self.rails_x_offset[x_index[1]]] - # create y offset list - if (k % 2 == 0): - y_off = k * (self.nand.height) - direct = 1 - else: - y_off = (k + 1) * (self.nand.height) - drc["minwidth_metal1"] - direct = - 1 - list_connect = [y_off + direct * self.nand.A_position.y, - y_off + direct * self.nand.B_position.y] - # connect based on the two list - for connect in list_connect: - x_offset = line_x_offset[list_connect.index(connect)] - self.add_rect(layer="metal1", - offset=[x_offset, connect], - width=self.x_off_nand - x_offset, - height=drc["minwidth_metal1"]) - self.add_via(layers = ("metal1", "via1", "metal2"), - offset=[x_offset + self.gap_between_rails, - connect - self.via_shift], - rotate=90) - # Extended of the top NAND2 to the left hand side input rails - if(k == self.number_of_outputs - 1): - x_offset = self.rails_x_offset[list_connect.index(connect)] - self.add_rect(layer="metal1", - offset=[x_offset, connect], - width=self.x_off_nand - x_offset, - height=drc["minwidth_metal1"]) - self.add_via(layers = ("metal1", "via1", "metal2"), - offset=[x_offset + self.gap_between_rails, - connect - self.via_shift], - rotate=90) + vertical1 = out_offset + vertical2 = vertical1 + vector(0, + (inv_vdd_offset.y - inv_out_offset.y) * y_dir + - output_shift) + horizontal1 = vector(inv_out_offset.x, + inv_vdd_offset.y - correct) + horizontal2 = horizontal1 + vector(self.rails_x_offset[inv_rout + 4] - inv_out_offset.x+ drc["minwidth_metal2"], + 0) + return [[vertical1,vertical2],[horizontal1,horizontal2]] - def route_vdd_gnd_from_rails_to_gates(self): - for k in range(self.number_of_outputs): - power_line_index = 3 - (k%2) - yoffset = k * self.inv.height - 0.5 * drc["minwidth_metal1"] - self.add_rect(layer="metal1", - offset=[self.rails_x_offset[power_line_index], - yoffset], - width=self.x_off_nand - self.rails_x_offset[power_line_index], - height=drc["minwidth_metal1"]) - self.add_via(layers = ("metal1", "via1", "metal2"), - offset=[self.rails_x_offset[power_line_index] + self.gap_between_rails, - yoffset - self.via_shift], - rotate=90) - - yoffset = (self.number_of_outputs * self.inv.height - - 0.5 * drc["minwidth_metal1"]) - self.add_rect(layer="metal1", - offset=[self.rails_x_offset[3], yoffset], - width=self.x_off_nand - self.rails_x_offset[3], - height=drc["minwidth_metal1"]) - self.add_rect(layer="metal1", - offset=[self.rails_x_offset[3], self.rail_height], - width=drc["minwidth_metal1"], - height=yoffset - self.rail_height) - self.add_via(layers = ("metal1", "via1", "metal2"), - offset=[self.rails_x_offset[3] + self.gap_between_rails, - self.rail_height - self.via_shift], - rotate=90) + def set_output_shift(self): + return 2 * drc["minwidth_metal1"] + + def get_nand_input_line_combination(self): + combination = [[4, 5], [6, 5], [4, 7], [6, 7]] + return combination + + def create_y_offsets(self,k): + # create y offset list + if (k % 2 == 0): + y_off = k * (self.nand.height) + direct = 1 + else: + y_off = (k + 1) * (self.nand.height) - drc["minwidth_metal1"] + direct = - 1 + correct =[0,0] + yoffset_nand_in = [y_off + direct * self.nand.A_position.y, + y_off + direct * self.nand.B_position.y] + return yoffset_nand_in, correct + + def get_via_correct(self): + return vector(0, self.via_shift) + + def get_vertical_metal(self): + return "metal1" + + def get_via_y(self): + return self.rail_height diff --git a/compiler/hierarchical_predecode3x8.py b/compiler/hierarchical_predecode3x8.py index 50fc6031..622a3268 100644 --- a/compiler/hierarchical_predecode3x8.py +++ b/compiler/hierarchical_predecode3x8.py @@ -1,6 +1,7 @@ from tech import drc import debug import design +from nand_3 import nand_3 from vector import vector from hierarchical_predecode import hierarchical_predecode @@ -18,6 +19,14 @@ class hierarchical_predecode3x8(hierarchical_predecode): self.create_layout() self.route() + def create_nand(self): + self.nand = nand_3(name="a_nand_3", + nmos_width=self.nmos_width, + height=self.bitcell_height) + + def set_rail_height(self): + self.rail_height = (self.number_of_outputs * self.nand.height + - 1.5 * drc["minwidth_metal2"]) def create_layout(self): self.create_rails() self.add_output_inverters() @@ -31,111 +40,53 @@ class hierarchical_predecode3x8(hierarchical_predecode): ["B[0]", "B[1]", "B[2]", "Z[0]", "vdd", "gnd"]] self.add_nand(connections) - def route_input_inverters(self): - # All conections of the inputs inverters [Inputs, outputs, vdd, gnd] - for inv_rout in range(self.number_of_inputs): - output_shift = 1.5 * drc["minwidth_metal1"] + def set_height(self): + self.height = 8 * self.nand.height - if (inv_rout % 2 == 0): - base_offset=[self.x_off_inv_1, inv_rout * self.inv.height ] - y_dir = 1 - else: - base_offset=[self.x_off_inv_1, 2 * self.inv.height - drc["minwidth_metal1"]] - y_dir = -1 - inv_out_offset = base_offset+self.inv.Z_position.scale(1,y_dir) - inv_in_offset = base_offset+self.inv.A_position.scale(1,y_dir) - inv_vdd_offset = base_offset+self.inv.vdd_position.scale(1,y_dir) - inv_gnd_offset = base_offset+self.inv.gnd_position.scale(1,y_dir) - # output connection - correct = y_dir * (output_shift + drc["minwidth_metal1"]) - off_via = [self.rails_x_offset[inv_rout + 5] + self.gap_between_rails, - inv_vdd_offset.y - self.via_shift - correct] - path1 = inv_out_offset + vector(0.5*drc["minwidth_metal1"], - - 1.5*drc["minwidth_metal1"] - correct) - path2 = vector(path1.x, - inv_vdd_offset.y + 0.5 * drc["minwidth_metal1"] - correct) - path3 = vector(self.rails_x_offset[inv_rout + 5] + drc["minwidth_metal2"], - path2.y) - self.add_path("metal1", [path1,path2,path3]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=off_via, - rotate=90) - self.route_input_inverters_input(inv_rout,inv_in_offset) - self.route_input_inverters_vdd(inv_vdd_offset) - self.route_input_inverters_gnd(inv_gnd_offset) + def cal_input_inverters_output(self,setup,output_shift,inv_rout): + y_dir,inv_in_offset,inv_out_offset,inv_vdd_offset,inv_gnd_offset = setup + correct = y_dir * (output_shift + drc["minwidth_metal1"]) - def route_nand_to_rails(self): - # This 2D array defines the connection mapping of the Nand3 gates to - # the rail - nand3_input_line_combination = [[5, 6, 7], [5, 6, 10], - [5, 9, 7], [5, 9, 10], - [8, 6, 7], [8, 6, 10], - [8, 9, 7], [8, 9, 10]] - for k in range(self.number_of_outputs): - index_lst = nand3_input_line_combination[k] - line_x_offset = [] - for index in index_lst: - line_x_offset.append(self.rails_x_offset[index]) + out_offset = inv_out_offset + vector(0, output_shift + correct) + vertical1 = out_offset + vertical2 = (vertical1.scale(1, 0) + inv_vdd_offset.scale(0, 1) + + vector(0, - correct)) + horizontal1 = vertical1 + horizontal2 = vector(self.rails_x_offset[inv_rout + 5] + drc["minwidth_metal2"], + vertical2.y) + return [[vertical1,vertical2],[horizontal1,horizontal2]] - if (k % 2 == 0): - y_off = k * (self.nand.height) - y_dir =1 - correct = [0,0,self.contact_shift] - else: - y_off = 2 * self.inv.height - drc["minwidth_metal1"] + (k - 1) * (self.nand.height) - y_dir = -1 - correct = [0,self.contact_shift,0] - yoffset_nand_in = [y_off + y_dir*self.nand.A_position[1], - y_off + y_dir*self.nand.B_position[1], - y_off + y_dir*self.nand.C_position[1]] + def set_output_shift(self): + return 1.5 * drc["minwidth_metal1"] - for i in range(self.number_of_inputs): - # Connecting the i-th input of Nand3 gate - self.add_rect(layer="metal1", - offset=[line_x_offset[i], yoffset_nand_in[i]], - width=self.x_off_nand - line_x_offset[i], - height=drc["minwidth_metal1"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[line_x_offset[i]+ self.gap_between_rails, - yoffset_nand_in[i] - self.via_shift - correct[i]], - rotate=90) - #Extended of the top NAND2 to the left hand side input rails - if(k == self.number_of_outputs - 1): - for i in range(self.number_of_inputs): - self.add_rect(layer="metal1", - offset=[self.rails_x_offset[i], yoffset_nand_in[i]], - width=self.x_off_nand - self.rails_x_offset[i], - height=drc["minwidth_metal1"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[self.rails_x_offset[i] + self.gap_between_rails, - yoffset_nand_in[i] - self.via_shift], - rotate=90) + def get_nand_input_line_combination(self): + combination = [[5, 6, 7], [5, 6, 10], + [5, 9, 7], [5, 9, 10], + [8, 6, 7], [8, 6, 10], + [8, 9, 7], [8, 9, 10]] + return combination - def route_vdd_gnd_from_rails_to_gates(self): - for k in range(self.number_of_outputs): - power_line_index = 4 - (k%2) - yoffset = k * self.inv.height - 0.5 * drc["minwidth_metal1"] - self.add_rect(layer="metal1", - offset=[self.rails_x_offset[power_line_index], yoffset], - width=self.x_off_nand - self.rails_x_offset[power_line_index], - height=drc["minwidth_metal1"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[self.rails_x_offset[power_line_index] + self.gap_between_rails, - yoffset - self.via_shift - self.contact_shift], - rotate=90) + def create_y_offsets(self,k): + if (k % 2 == 0): + y_off = k * (self.nand.height) + y_dir =1 + correct = [0,0,self.contact_shift] + else: + y_off = 2 * self.inv.height - drc["minwidth_metal1"] + (k - 1) * (self.nand.height) + y_dir = -1 + correct = [0,self.contact_shift,0] + yoffset_nand_in = [y_off + y_dir*self.nand.A_position[1], + y_off + y_dir*self.nand.B_position[1], + y_off + y_dir*self.nand.C_position[1]] + return yoffset_nand_in, correct + def get_via_correct(self): + return vector(0, self.via_shift+self.contact_shift) + + def get_vertical_metal(self): + return "metal2" + + def get_via_y(self): yoffset = (self.number_of_outputs * self.inv.height - 0.5 * drc["minwidth_metal1"]) - self.add_rect(layer="metal1", - offset=[self.rails_x_offset[4], yoffset], - width=self.x_off_nand - self.rails_x_offset[4], - height=drc["minwidth_metal1"]) - - self.add_rect(layer="metal2", - offset=[self.rails_x_offset[4], self.rail_height], - width=drc["minwidth_metal2"], - height=yoffset - self.rail_height) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[self.rails_x_offset[4] + self.gap_between_rails - self.via_shift, - yoffset - self.via_shift - self.contact_shift], - rotate=90) + return yoffset