Convert pnand+pinv to pand in decoders.

This commit is contained in:
mrg 2020-03-06 13:26:40 -08:00
parent 1a2efd77ad
commit 23501c7b35
5 changed files with 143 additions and 249 deletions

View File

@ -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.nand2)
self.nand3 = factory.create(module_type="pnand3",
self.add_mod(self.and2)
self.and3 = factory.create(module_type="pand3",
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],
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"))
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"))
row_index = row_index + 1
elif (self.num_inputs > 5):
@ -510,36 +461,26 @@ 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:
self.copy_layout_pin(pre, "vdd")

View File

@ -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",
self.and_mod = factory.create(module_type="pand2",
height=self.cell_height)
elif inputs==3:
self.nand = factory.create(module_type="pnand3",
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,
offset = vector(self.x_off_and, y_off)
self.and_inst[and_input].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)
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,7 +145,7 @@ 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.
# 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)
@ -187,28 +157,19 @@ class hierarchical_predecode(design.design):
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):
"""
Route all conections of the inputs inverters [Inputs, outputs, vdd, gnd]
@ -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):
def route_and_to_rails(self):
# This 2D array defines the connection mapping
nand_input_line_combination = self.get_nand_input_line_combination()
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]
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
# 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)

View File

@ -27,31 +27,29 @@ 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()
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"],

View File

@ -27,16 +27,15 @@ class hierarchical_predecode3x8(hierarchical_predecode):
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):
"""
@ -49,13 +48,12 @@ 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"],

View File

@ -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,21 +194,20 @@ 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 """
# PMOS1 drain