From 23501c7b352a32b9f87b77d7eda43d92a5c1bc51 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 6 Mar 2020 13:26:40 -0800 Subject: [PATCH] Convert pnand+pinv to pand in decoders. --- compiler/modules/hierarchical_decoder.py | 163 ++++++----------- compiler/modules/hierarchical_predecode.py | 167 +++++++----------- compiler/modules/hierarchical_predecode2x4.py | 24 ++- compiler/modules/hierarchical_predecode3x8.py | 32 ++-- compiler/pgates/pnand3.py | 6 +- 5 files changed, 143 insertions(+), 249 deletions(-) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index f9c21619..6e98c5e0 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -20,8 +20,7 @@ class hierarchical_decoder(design.design): def __init__(self, name, rows): design.design.__init__(self, name) - self.NAND_FORMAT = "DEC_NAND_{0}" - self.INV_FORMAT = "DEC_INV_{0}" + self.AND_FORMAT = "DEC_AND_{0}" self.pre2x4_inst = [] self.pre3x8_inst = [] @@ -58,12 +57,12 @@ class hierarchical_decoder(design.design): self.inv = factory.create(module_type="pinv", height=self.cell_height) self.add_mod(self.inv) - self.nand2 = factory.create(module_type="pnand2", + self.and2 = factory.create(module_type="pand2", + height=self.cell_height) + self.add_mod(self.and2) + self.and3 = factory.create(module_type="pand3", height=self.cell_height) - self.add_mod(self.nand2) - self.nand3 = factory.create(module_type="pnand3", - height=self.cell_height) - self.add_mod(self.nand3) + self.add_mod(self.and3) self.add_decoders() @@ -143,9 +142,9 @@ class hierarchical_decoder(design.design): # Calculates height and width of row-decoder if (self.num_inputs == 4 or self.num_inputs == 5): - nand_width = self.nand2.width + nand_width = self.and2.width else: - nand_width = self.nand3.width + nand_width = self.and3.width self.internal_routing_width = self.m2_pitch * self.total_number_of_predecoder_outputs self.row_decoder_height = self.inv.height * self.rows @@ -309,33 +308,32 @@ class hierarchical_decoder(design.design): self.pre3x8_inst[num].place(offset) def create_row_decoder(self): - """ Create the row-decoder by placing NAND2/NAND3 and Inverters + """ Create the row-decoder by placing AND2/AND3 and Inverters and add the primary decoder output pins. """ if (self.num_inputs >= 4): - self.create_decoder_nand_array() - self.create_decoder_inv_array() + self.create_decoder_and_array() - def create_decoder_nand_array(self): - """ Add a column of NAND gates for final decode """ + def create_decoder_and_array(self): + """ Add a column of AND gates for final decode """ - self.nand_inst = [] + self.and_inst = [] - # Row Decoder NAND GATE array for address inputs <5. + # Row Decoder AND GATE array for address inputs <5. if (self.num_inputs == 4 or self.num_inputs == 5): for i in range(len(self.predec_groups[0])): for j in range(len(self.predec_groups[1])): row = len(self.predec_groups[0]) * j + i if (row < self.rows): - name = self.NAND_FORMAT.format(row) - self.nand_inst.append(self.add_inst(name=name, - mod=self.nand2)) + name = self.AND_FORMAT.format(row) + self.and_inst.append(self.add_inst(name=name, + mod=self.and2)) pins =["out_{0}".format(i), "out_{0}".format(j + len(self.predec_groups[0])), - "Z_{0}".format(row), + "decode_{0}".format(row), "vdd", "gnd"] self.connect_inst(pins) - # Row Decoder NAND GATE array for address inputs >5. + # Row Decoder AND GATE array for address inputs >5. elif (self.num_inputs > 5): for i in range(len(self.predec_groups[0])): for j in range(len(self.predec_groups[1])): @@ -344,104 +342,57 @@ class hierarchical_decoder(design.design): + len(self.predec_groups[0]) * j + i if (row < self.rows): - name = self.NAND_FORMAT.format(row) - self.nand_inst.append(self.add_inst(name=name, - mod=self.nand3)) + name = self.AND_FORMAT.format(row) + self.and_inst.append(self.add_inst(name=name, + mod=self.and3)) pins = ["out_{0}".format(i), "out_{0}".format(j + len(self.predec_groups[0])), "out_{0}".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])), - "Z_{0}".format(row), + "decode_{0}".format(row), "vdd", "gnd"] self.connect_inst(pins) - def create_decoder_inv_array(self): - """ - Add a column of INV gates for the decoder. - """ - - self.inv_inst = [] - for row in range(self.rows): - name = self.INV_FORMAT.format(row) - self.inv_inst.append(self.add_inst(name=name, - mod=self.inv)) - self.connect_inst(args=["Z_{0}".format(row), - "decode_{0}".format(row), - "vdd", "gnd"]) - - def place_decoder_inv_array(self): - """ - Place the column of INV gates for the decoder above the predecoders - and to the right of the NAND decoders. - """ - - if (self.num_inputs == 4 or self.num_inputs == 5): - x_off = self.internal_routing_width + self.nand2.width - else: - x_off = self.internal_routing_width + self.nand3.width - - for row in range(self.rows): - if (row % 2 == 0): - inv_row_height = self.inv.height * row - mirror = "R0" - else: - inv_row_height = self.inv.height * (row + 1) - mirror = "MX" - y_off = inv_row_height - offset = vector(x_off, y_off) - self.inv_inst[row].place(offset=offset, - mirror=mirror) - def place_row_decoder(self): """ - Place the row-decoder by placing NAND2/NAND3 and Inverters + Place the row-decoder by placing AND2/AND3 and Inverters and add the primary decoder output pins. """ if (self.num_inputs >= 4): - self.place_decoder_nand_array() - self.place_decoder_inv_array() + self.place_decoder_and_array() self.route_decoder() - def place_decoder_nand_array(self): - """ Add a column of NAND gates for final decode """ + def place_decoder_and_array(self): + """ Add a column of AND gates for final decode """ - # Row Decoder NAND GATE array for address inputs <5. + # Row Decoder AND GATE array for address inputs <5. if (self.num_inputs == 4 or self.num_inputs == 5): - self.place_nand_array(nand_mod=self.nand2) + self.place_and_array(and_mod=self.and2) - # Row Decoder NAND GATE array for address inputs >5. + # Row Decoder AND GATE array for address inputs >5. # FIXME: why this correct offset?) elif (self.num_inputs > 5): - self.place_nand_array(nand_mod=self.nand3) + self.place_and_array(and_mod=self.and3) - def place_nand_array(self, nand_mod): - """ Add a column of NAND gates for the decoder above the predecoders.""" + def place_and_array(self, and_mod): + """ Add a column of AND gates for the decoder above the predecoders.""" for row in range(self.rows): if ((row % 2) == 0): - y_off = nand_mod.height * row + y_off = and_mod.height * row mirror = "R0" else: - y_off = nand_mod.height * (row + 1) + y_off = and_mod.height * (row + 1) mirror = "MX" - self.nand_inst[row].place(offset=[self.internal_routing_width, y_off], - mirror=mirror) + self.and_inst[row].place(offset=[self.internal_routing_width, y_off], + mirror=mirror) def route_decoder(self): - """ Route the nand to inverter in the decoder and add the pins. """ + """ Add the pins. """ for row in range(self.rows): - - # route nand output to output inv input - zr_pos = self.nand_inst[row].get_pin("Z").rc() - al_pos = self.inv_inst[row].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]) - - z_pin = self.inv_inst[row].get_pin("Z") + z_pin = self.and_inst[row].get_pin("Z") self.add_layout_pin(text="decode_{0}".format(row), layer="m1", offset=z_pin.ll(), @@ -484,12 +435,12 @@ class hierarchical_decoder(design.design): self.route_predecode_rail_m3(predecode_name, pin) def route_rails_to_decoder(self): - """ Use the self.predec_groups to determine the connections to the decoder NAND gates. - Inputs of NAND2/NAND3 gates come from different groups. + """ Use the self.predec_groups to determine the connections to the decoder AND gates. + Inputs of AND2/AND3 gates come from different groups. For example for these groups [ [0,1,2,3] ,[4,5,6,7], - [8,9,10,11,12,13,14,15] ] the first NAND3 inputs are connected to - [0,4,8] and second NAND3 is connected to [0,4,9] ........... and the - 128th NAND3 is connected to [3,7,15] + [8,9,10,11,12,13,14,15] ] the first AND3 inputs are connected to + [0,4,8] and second AND3 is connected to [0,4,9] ........... and the + 128th AND3 is connected to [3,7,15] """ row_index = 0 if (self.num_inputs == 4 or self.num_inputs == 5): @@ -498,9 +449,9 @@ class hierarchical_decoder(design.design): # FIXME: convert to connect_bus? if (row_index < self.rows): predecode_name = "predecode_{}".format(index_A) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A")) - predecode_name = "predecode_{}".format(index_B) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B")) + self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("A")) + predecode_name = "predecode_{}".format(index_B) + self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("B")) row_index = row_index + 1 elif (self.num_inputs > 5): @@ -510,35 +461,25 @@ class hierarchical_decoder(design.design): # FIXME: convert to connect_bus? if (row_index < self.rows): predecode_name = "predecode_{}".format(index_A) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("A")) + self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("A")) predecode_name = "predecode_{}".format(index_B) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("B")) + self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("B")) predecode_name = "predecode_{}".format(index_C) - self.route_predecode_rail(predecode_name, self.nand_inst[row_index].get_pin("C")) + self.route_predecode_rail(predecode_name, self.and_inst[row_index].get_pin("C")) row_index = row_index + 1 def route_vdd_gnd(self): """ Add a pin for each row of vdd/gnd which are must-connects next level up. """ # The vias will be placed in the center and right of the cells, respectively. - xoffset = self.nand_inst[0].rx() + xoffset = self.and_inst[0].rx() for num in range(0, self.rows): for pin_name in ["vdd", "gnd"]: # The nand and inv are the same height rows... - supply_pin = self.nand_inst[num].get_pin(pin_name) + supply_pin = self.and_inst[num].get_pin(pin_name) pin_pos = vector(xoffset, supply_pin.cy()) self.add_power_pin(name=pin_name, loc=pin_pos) - - # Make a redundant rail too - for num in range(0, self.rows, 2): - for pin_name in ["vdd", "gnd"]: - start = self.nand_inst[num].get_pin(pin_name).lc() - end = self.inv_inst[num].get_pin(pin_name).rc() - mid = (start + end).scale(0.5, 0.5) - self.add_rect_center(layer="m1", - offset=mid, - width=end.x - start.x) # Copy the pins from the predecoders for pre in self.pre2x4_inst + self.pre3x8_inst: diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 88bae534..ccee34a9 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -32,61 +32,58 @@ class hierarchical_predecode(design.design): self.add_pin("gnd", "GROUND") def add_modules(self): - """ Add the INV and NAND gate modules """ + """ Add the INV and AND gate modules """ self.inv = factory.create(module_type="pinv", height=self.cell_height) self.add_mod(self.inv) - self.add_nand(self.number_of_inputs) - self.add_mod(self.nand) + self.add_and(self.number_of_inputs) + self.add_mod(self.and_mod) - def add_nand(self, inputs): + def add_and(self, inputs): """ Create the NAND for the predecode input stage """ if inputs==2: - self.nand = factory.create(module_type="pnand2", - height=self.cell_height) + self.and_mod = factory.create(module_type="pand2", + height=self.cell_height) elif inputs==3: - self.nand = factory.create(module_type="pnand3", - height=self.cell_height) + self.and_mod = factory.create(module_type="pand3", + height=self.cell_height) else: debug.error("Invalid number of predecode inputs: {}".format(inputs), -1) def setup_layout_constraints(self): - self.height = self.number_of_outputs * self.nand.height + self.height = self.number_of_outputs * self.and_mod.height # x offset for input inverters self.x_off_inv_1 = self.number_of_inputs*self.m2_pitch - # x offset to NAND decoder includes the left rails, mid rails and inverters, plus two extra m2 pitches - self.x_off_nand = self.x_off_inv_1 + self.inv.width + (2*self.number_of_inputs + 2) * self.m2_pitch + # x offset to AND decoder includes the left rails, mid rails and inverters, plus two extra m2 pitches + self.x_off_and = self.x_off_inv_1 + self.inv.width + (2*self.number_of_inputs + 2) * self.m2_pitch # x offset to output inverters - self.x_off_inv_2 = self.x_off_nand + self.nand.width - - # Height width are computed - self.width = self.x_off_inv_2 + self.inv.width + self.width = self.x_off_and + self.and_mod.width def route_rails(self): """ Create all of the rails for the inputs and vdd/gnd/inputs_bar/inputs """ input_names = ["in_{}".format(x) for x in range(self.number_of_inputs)] - offset = vector(0.5*self.m2_width,2*self.m1_width) + offset = vector(0.5 * self.m2_width, self.m1_pitch) self.input_rails = self.create_vertical_pin_bus(layer="m2", pitch=self.m2_pitch, offset=offset, names=input_names, - length=self.height - 2*self.m1_width) + length=self.height - 2 * self.m1_pitch) invert_names = ["Abar_{}".format(x) for x in range(self.number_of_inputs)] non_invert_names = ["A_{}".format(x) for x in range(self.number_of_inputs)] decode_names = invert_names + non_invert_names - offset = vector(self.x_off_inv_1 + self.inv.width + 2*self.m2_pitch, 2*self.m1_width) + offset = vector(self.x_off_inv_1 + self.inv.width + 2 * self.m2_pitch, self.m1_pitch) self.decode_rails = self.create_vertical_bus(layer="m2", pitch=self.m2_pitch, offset=offset, names=decode_names, - length=self.height - 2*self.m1_width) + length=self.height - 2 * self.m1_pitch) def create_input_inverters(self): """ Create the input inverters to invert input signals for the decode stage. """ @@ -112,62 +109,35 @@ class hierarchical_predecode(design.design): self.in_inst[inv_num].place(offset=offset, mirror=mirror) - def create_output_inverters(self): - """ Create inverters for the inverted output decode signals. """ - self.inv_inst = [] - for inv_num in range(self.number_of_outputs): - name = "pre_nand_inv_{}".format(inv_num) - self.inv_inst.append(self.add_inst(name=name, - mod=self.inv)) - self.connect_inst(["Z_{}".format(inv_num), - "out_{}".format(inv_num), - "vdd", "gnd"]) + def create_and_array(self, connections): + """ Create the AND stage for the decodes """ + self.and_inst = [] + for and_input in range(self.number_of_outputs): + inout = str(self.number_of_inputs) + "x" + str(self.number_of_outputs) + name = "Xpre{0}_and_{1}".format(inout, and_input) + self.and_inst.append(self.add_inst(name=name, + mod=self.and_mod)) + self.connect_inst(connections[and_input]) - - def place_output_inverters(self): - """ Place inverters for the inverted output decode signals. """ - for inv_num in range(self.number_of_outputs): - if (inv_num % 2 == 0): - y_off = inv_num * self.inv.height + def place_and_array(self): + """ Place the AND stage for the decodes """ + for and_input in range(self.number_of_outputs): + # inout = str(self.number_of_inputs) + "x" + str(self.number_of_outputs) + if (and_input % 2 == 0): + y_off = and_input * self.and_mod.height mirror = "R0" else: - y_off =(inv_num + 1)*self.inv.height + y_off = (and_input + 1) * self.and_mod.height mirror = "MX" - offset = vector(self.x_off_inv_2, y_off) - self.inv_inst[inv_num].place(offset=offset, - mirror=mirror) - - def create_nand_array(self,connections): - """ Create the NAND stage for the decodes """ - self.nand_inst = [] - for nand_input in range(self.number_of_outputs): - inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs) - name = "Xpre{0}_nand_{1}".format(inout,nand_input) - self.nand_inst.append(self.add_inst(name=name, - mod=self.nand)) - self.connect_inst(connections[nand_input]) - - - def place_nand_array(self): - """ Place the NAND stage for the decodes """ - for nand_input in range(self.number_of_outputs): - inout = str(self.number_of_inputs)+"x"+str(self.number_of_outputs) - if (nand_input % 2 == 0): - y_off = nand_input * self.inv.height - mirror = "R0" - else: - y_off = (nand_input + 1) * self.inv.height - mirror = "MX" - offset = vector(self.x_off_nand, y_off) - self.nand_inst[nand_input].place(offset=offset, - mirror=mirror) - + offset = vector(self.x_off_and, y_off) + self.and_inst[and_input].place(offset=offset, + mirror=mirror) def route(self): self.route_input_inverters() self.route_inputs_to_rails() - self.route_nand_to_rails() - self.route_output_inverters() + self.route_and_to_rails() + self.route_output_and() self.route_vdd_gnd() def route_inputs_to_rails(self): @@ -175,39 +145,30 @@ class hierarchical_predecode(design.design): for num in range(self.number_of_inputs): # route one signal next to each vdd/gnd rail since this is # typically where the p/n devices are and there are no - # pins in the nand gates. - y_offset = (num+self.number_of_inputs) * self.inv.height + contact.m1_via.width + self.m1_space - in_pin = "in_{}".format(num) + # pins in the and gates. + y_offset = (num + self.number_of_inputs) * self.inv.height + contact.m1_via.width + self.m1_space + in_pin = "in_{}".format(num) a_pin = "A_{}".format(num) - in_pos = vector(self.input_rails[in_pin].x,y_offset) - a_pos = vector(self.decode_rails[a_pin].x,y_offset) - self.add_path("m1",[in_pos, a_pos]) - self.add_via_center(layers = self.m1_stack, + in_pos = vector(self.input_rails[in_pin].x, y_offset) + a_pos = vector(self.decode_rails[a_pin].x, y_offset) + self.add_path("m1", [in_pos, a_pos]) + self.add_via_center(layers=self.m1_stack, offset=[self.input_rails[in_pin].x, y_offset]) - self.add_via_center(layers = self.m1_stack, + self.add_via_center(layers=self.m1_stack, offset=[self.decode_rails[a_pin].x, y_offset]) - def route_output_inverters(self): + def route_output_and(self): """ - Route all conections of the outputs inverters + Route all conections of the outputs and gates """ for num in range(self.number_of_outputs): - # route nand output to output inv input - zr_pos = self.nand_inst[num].get_pin("Z").rc() - al_pos = self.inv_inst[num].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]) - - z_pin = self.inv_inst[num].get_pin("Z") + z_pin = self.and_inst[num].get_pin("Z") self.add_layout_pin(text="out_{}".format(num), layer="m1", offset=z_pin.ll(), height=z_pin.height(), width=z_pin.width()) - def route_input_inverters(self): """ @@ -219,7 +180,7 @@ class hierarchical_predecode(design.design): #add output so that it is just below the vdd or gnd rail # since this is where the p/n devices are and there are no - # pins in the nand gates. + # pins in the and gates. y_offset = (inv_num+1) * self.inv.height - 3*self.m1_space inv_out_pos = self.in_inst[inv_num].get_pin("Z").rc() right_pos = inv_out_pos + vector(self.inv.width - self.inv.get_pin("Z").lx(),0) @@ -236,13 +197,12 @@ class hierarchical_predecode(design.design): self.add_via_center(layers=self.m1_stack, offset=in_pos) - - def route_nand_to_rails(self): - # This 2D array defines the connection mapping - nand_input_line_combination = self.get_nand_input_line_combination() + def route_and_to_rails(self): + # This 2D array defines the connection mapping + and_input_line_combination = self.get_and_input_line_combination() for k in range(self.number_of_outputs): - # create x offset list - index_lst= nand_input_line_combination[k] + # create x offset list + index_lst= and_input_line_combination[k] if self.number_of_inputs == 2: gate_lst = ["A","B"] @@ -251,35 +211,32 @@ class hierarchical_predecode(design.design): # this will connect pins A,B or A,B,C for rail_pin,gate_pin in zip(index_lst,gate_lst): - pin_pos = self.nand_inst[k].get_pin(gate_pin).lc() + pin_pos = self.and_inst[k].get_pin(gate_pin).lc() rail_pos = vector(self.decode_rails[rail_pin].x, pin_pos.y) self.add_path("m1", [rail_pos, pin_pos]) self.add_via_center(layers=self.m1_stack, offset=rail_pos) - - - def route_vdd_gnd(self): """ 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 in_xoffset = self.in_inst[0].rx() + self.m1_space - out_xoffset = self.inv_inst[0].lx() - self.m1_space - for num in range(0,self.number_of_outputs): + # out_xoffset = self.and_inst[0].cx() + self.m1_space + for num in range(0, self.number_of_outputs): # this will result in duplicate polygons for rails, but who cares # Route both supplies for n in ["vdd", "gnd"]: - nand_pin = self.nand_inst[num].get_pin(n) - supply_offset = nand_pin.ll().scale(0,1) + and_pin = self.and_inst[num].get_pin(n) + supply_offset = and_pin.ll().scale(0, 1) self.add_rect(layer="m1", offset=supply_offset, - width=self.inv_inst[num].rx()) + width=self.and_inst[num].rx()) # Add pins in two locations - for xoffset in [in_xoffset, out_xoffset]: - pin_pos = vector(xoffset, nand_pin.cy()) + for xoffset in [in_xoffset]: + pin_pos = vector(xoffset, and_pin.cy()) self.add_power_pin(n, pin_pos) diff --git a/compiler/modules/hierarchical_predecode2x4.py b/compiler/modules/hierarchical_predecode2x4.py index f05f54b0..b1aacc5a 100644 --- a/compiler/modules/hierarchical_predecode2x4.py +++ b/compiler/modules/hierarchical_predecode2x4.py @@ -27,33 +27,31 @@ class hierarchical_predecode2x4(hierarchical_predecode): self.add_pins() self.add_modules() self.create_input_inverters() - self.create_output_inverters() - connections =[["inbar_0", "inbar_1", "Z_0", "vdd", "gnd"], - ["in_0", "inbar_1", "Z_1", "vdd", "gnd"], - ["inbar_0", "in_1", "Z_2", "vdd", "gnd"], - ["in_0", "in_1", "Z_3", "vdd", "gnd"]] - self.create_nand_array(connections) + connections =[["inbar_0", "inbar_1", "out_0", "vdd", "gnd"], + ["in_0", "inbar_1", "out_1", "vdd", "gnd"], + ["inbar_0", "in_1", "out_2", "vdd", "gnd"], + ["in_0", "in_1", "out_3", "vdd", "gnd"]] + self.create_and_array(connections) def create_layout(self): """ The general organization is from left to right: 1) a set of M2 rails for input signals 2) a set of inverters to invert input signals 3) a set of M2 rails for the vdd, gnd, inverted inputs, inputs - 4) a set of NAND gates for inversion + 4) a set of AND gates for inversion """ self.setup_layout_constraints() self.route_rails() self.place_input_inverters() - self.place_output_inverters() - self.place_nand_array() + self.place_and_array() self.route() self.add_boundary() - self.DRC_LVS() + self.DRC_LVS() - def get_nand_input_line_combination(self): - """ These are the decoder connections of the NAND gates to the A,B pins """ + def get_and_input_line_combination(self): + """ These are the decoder connections of the AND gates to the A,B pins """ combination = [["Abar_0", "Abar_1"], ["A_0", "Abar_1"], ["Abar_0", "A_1"], ["A_0", "A_1"]] - return combination \ No newline at end of file + return combination diff --git a/compiler/modules/hierarchical_predecode3x8.py b/compiler/modules/hierarchical_predecode3x8.py index 20b629bb..4f2294f1 100644 --- a/compiler/modules/hierarchical_predecode3x8.py +++ b/compiler/modules/hierarchical_predecode3x8.py @@ -20,26 +20,25 @@ class hierarchical_predecode3x8(hierarchical_predecode): hierarchical_predecode.__init__(self, name, 3, height) self.create_netlist() - if not OPTS.netlist_only: + if not OPTS.netlist_only: self.create_layout() def create_netlist(self): self.add_pins() self.add_modules() self.create_input_inverters() - self.create_output_inverters() - connections=[["inbar_0", "inbar_1", "inbar_2", "Z_0", "vdd", "gnd"], - ["in_0", "inbar_1", "inbar_2", "Z_1", "vdd", "gnd"], - ["inbar_0", "in_1", "inbar_2", "Z_2", "vdd", "gnd"], - ["in_0", "in_1", "inbar_2", "Z_3", "vdd", "gnd"], - ["inbar_0", "inbar_1", "in_2", "Z_4", "vdd", "gnd"], - ["in_0", "inbar_1", "in_2", "Z_5", "vdd", "gnd"], - ["inbar_0", "in_1", "in_2", "Z_6", "vdd", "gnd"], - ["in_0", "in_1", "in_2", "Z_7", "vdd", "gnd"]] - self.create_nand_array(connections) + connections=[["inbar_0", "inbar_1", "inbar_2", "out_0", "vdd", "gnd"], + ["in_0", "inbar_1", "inbar_2", "out_1", "vdd", "gnd"], + ["inbar_0", "in_1", "inbar_2", "out_2", "vdd", "gnd"], + ["in_0", "in_1", "inbar_2", "out_3", "vdd", "gnd"], + ["inbar_0", "inbar_1", "in_2", "out_4", "vdd", "gnd"], + ["in_0", "inbar_1", "in_2", "out_5", "vdd", "gnd"], + ["inbar_0", "in_1", "in_2", "out_6", "vdd", "gnd"], + ["in_0", "in_1", "in_2", "out_7", "vdd", "gnd"]] + self.create_and_array(connections) def create_layout(self): - """ + """ The general organization is from left to right: 1) a set of M2 rails for input signals 2) a set of inverters to invert input signals @@ -49,20 +48,19 @@ class hierarchical_predecode3x8(hierarchical_predecode): self.setup_layout_constraints() self.route_rails() self.place_input_inverters() - self.place_output_inverters() - self.place_nand_array() + self.place_and_array() self.route() self.add_boundary() self.DRC_LVS() - def get_nand_input_line_combination(self): + def get_and_input_line_combination(self): """ These are the decoder connections of the NAND gates to the A,B,C pins """ combination = [["Abar_0", "Abar_1", "Abar_2"], ["A_0", "Abar_1", "Abar_2"], ["Abar_0", "A_1", "Abar_2"], ["A_0", "A_1", "Abar_2"], - ["Abar_0", "Abar_1", "A_2"], + ["Abar_0", "Abar_1", "A_2"], ["A_0", "Abar_1", "A_2"], ["Abar_0", "A_1", "A_2"], ["A_0", "A_1", "A_2"]] - return combination \ No newline at end of file + return combination diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index a9fd19b7..2bbdaf91 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -185,6 +185,7 @@ class pnand3(pgate.pgate): def route_inputs(self): """ Route the A and B and C inputs """ + m1_pitch = self.m1_space + contact.m1_via.first_layer_height # Put B right on the well line self.inputB_yoffset = self.nwell_y_offset self.route_input_gate(self.pmos2_inst, @@ -193,20 +194,19 @@ class pnand3(pgate.pgate): "B", position="center") - self.inputC_yoffset = self.inputB_yoffset - self.m1_pitch + self.inputC_yoffset = self.inputB_yoffset - m1_pitch self.route_input_gate(self.pmos3_inst, self.nmos3_inst, self.inputC_yoffset, "C", position="center") - self.inputA_yoffset = self.inputB_yoffset + self.m1_pitch + self.inputA_yoffset = self.inputB_yoffset + m1_pitch self.route_input_gate(self.pmos1_inst, self.nmos1_inst, self.inputA_yoffset, "A", position="center") - def route_output(self): """ Route the Z output """