Move pnand outputs to M1. Debug hierarchical decoder multirow.

This commit is contained in:
mrg 2020-04-14 10:52:25 -07:00
parent 2e67d44cd7
commit 43dcf675a1
4 changed files with 139 additions and 68 deletions

View File

@ -199,7 +199,8 @@ class hierarchical_decoder(design.design):
self.input_routing_width = (self.num_inputs + 1) * self.m2_pitch
# Calculates height and width of hierarchical decoder
self.height = max(self.predecoder_height, self.row_decoder_height)
# Add extra pitch for good measure
self.height = max(self.predecoder_height, self.row_decoder_height) + self.m3_pitch
self.width = self.input_routing_width + self.predecoder_width \
+ self.internal_routing_width \
+ self.decoders_per_row * nand_width + self.inv.width
@ -261,7 +262,10 @@ class hierarchical_decoder(design.design):
self.route_input_bus(decoder_offset, input_offset)
def route_input_bus(self, input_offset, output_offset):
""" Route a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """
"""
Route a vertical M2 coordinate to another
vertical M2 coordinate to the predecode inputs
"""
self.add_via_center(layers=self.m2_stack,
offset=input_offset)
@ -471,10 +475,10 @@ class hierarchical_decoder(design.design):
names=input_bus_names,
length=self.height)
self.route_bus_to_predecodes()
self.route_predecodes_to_bus()
self.route_bus_to_decoder()
def route_bus_to_predecodes(self):
def route_predecodes_to_bus(self):
"""
Iterates through all of the predecodes
and connects to the rails including the offsets
@ -517,7 +521,7 @@ class hierarchical_decoder(design.design):
if (output_index < self.num_outputs):
row_index = math.floor(output_index / self.decoders_per_row)
row_remainder = (output_index % self.decoders_per_row)
row_offset = row_index * self.and_inst[0].height + (2 * row_remainder + 4) * self.m1_pitch
row_offset = row_index * self.and_inst[0].height + (2 * row_remainder + 1) * self.m3_pitch
predecode_name = "predecode_{}".format(index_A)
self.route_predecode_bus_outputs(predecode_name,
self.and_inst[output_index].get_pin("A"),
@ -525,7 +529,7 @@ class hierarchical_decoder(design.design):
predecode_name = "predecode_{}".format(index_B)
self.route_predecode_bus_outputs(predecode_name,
self.and_inst[output_index].get_pin("B"),
row_offset + self.m1_pitch)
row_offset + self.m3_pitch)
output_index = output_index + 1
elif (self.num_inputs > 5):
@ -536,7 +540,7 @@ class hierarchical_decoder(design.design):
if (output_index < self.num_outputs):
row_index = math.floor(output_index / self.decoders_per_row)
row_remainder = (output_index % self.decoders_per_row)
row_offset = row_index * self.and_inst[0].height + (3 * row_remainder + 4) * self.m1_pitch
row_offset = row_index * self.and_inst[0].height + (3 * row_remainder + 1) * self.m3_pitch
predecode_name = "predecode_{}".format(index_A)
self.route_predecode_bus_outputs(predecode_name,
self.and_inst[output_index].get_pin("A"),
@ -544,11 +548,11 @@ class hierarchical_decoder(design.design):
predecode_name = "predecode_{}".format(index_B)
self.route_predecode_bus_outputs(predecode_name,
self.and_inst[output_index].get_pin("B"),
row_offset + self.m1_pitch)
row_offset + self.m3_pitch)
predecode_name = "predecode_{}".format(index_C)
self.route_predecode_bus_outputs(predecode_name,
self.and_inst[output_index].get_pin("C"),
row_offset + 2 * self.m1_pitch)
row_offset + 2 * self.m3_pitch)
output_index = output_index + 1
def route_vdd_gnd(self):
@ -557,13 +561,19 @@ class hierarchical_decoder(design.design):
must-connects next level up.
"""
# The vias will be placed in the center and right of the cells, respectively.
xoffset = self.and_inst[0].rx()
# The vias will be placed at the right of the cells.
xoffset = max(x.rx() for x in self.and_inst)
for num in range(0, self.num_outputs):
# Only add the power pin for the 1st in each row
if num % self.decoders_per_row:
continue
for pin_name in ["vdd", "gnd"]:
# The nand and inv are the same height rows...
supply_pin = self.and_inst[num].get_pin(pin_name)
pin_pos = vector(xoffset, supply_pin.cy())
self.add_path("m1",
[supply_pin.lc(), vector(xoffset, supply_pin.cy())])
self.add_power_pin(name=pin_name,
loc=pin_pos)

View File

@ -98,7 +98,7 @@ class pnand2(pgate.pgate):
# metal spacing to allow contacts on any layer
self.input_spacing = max(self.poly_space + contact.poly_contact.first_layer_width,
self.m1_space + contact.m1_via.first_layer_width,
self.m2_space + contact.m2_via.first_layer_width,
self.m2_space + contact.m2_via.first_layer_width,
self.m3_space + contact.m2_via.second_layer_width)
@ -173,13 +173,15 @@ class pnand2(pgate.pgate):
0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos_nd.active_height))
def add_well_contacts(self):
"""
"""
Add n/p well taps to the layout and connect to supplies
AFTER the wells are created
"""
self.add_nwell_contact(self.pmos, self.pmos2_pos)
self.add_pwell_contact(self.nmos_nd, self.nmos2_pos)
self.add_nwell_contact(self.pmos,
self.pmos2_pos + vector(self.m1_pitch, 0))
self.add_pwell_contact(self.nmos_nd,
self.nmos2_pos + vector(self.m1_pitch, 0))
def connect_rails(self):
""" Connect the nmos and pmos to its respective power rails """
@ -197,7 +199,7 @@ class pnand2(pgate.pgate):
self.nmos2_inst,
inputB_yoffset,
"B",
position="right")
position="center")
# This will help with the wells and the input/output placement
self.inputA_yoffset = self.pmos2_inst.by() - self.poly_extend_active \
@ -209,6 +211,7 @@ class pnand2(pgate.pgate):
def route_output(self):
""" Route the Z output """
# PMOS1 drain
pmos_pin = self.pmos1_inst.get_pin("D")
top_pin_offset = pmos_pin.center()
@ -217,29 +220,46 @@ class pnand2(pgate.pgate):
bottom_pin_offset = nmos_pin.center()
# Output pin
out_offset = vector(nmos_pin.center().x + self.m1_pitch,
c_pin = self.get_pin("B")
out_offset = vector(c_pin.cx() + self.m1_pitch,
self.inputA_yoffset)
# Midpoints of the L routes go horizontal first then vertical
mid1_offset = vector(out_offset.x, top_pin_offset.y)
# This routes on M2
# # Midpoints of the L routes go horizontal first then vertical
# mid1_offset = vector(out_offset.x, top_pin_offset.y)
# mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
# # Non-preferred active contacts
# self.add_via_center(layers=self.m1_stack,
# directions=("V", "H"),
# offset=pmos_pin.center())
# # Non-preferred active contacts
# self.add_via_center(layers=self.m1_stack,
# directions=("V", "H"),
# offset=nmos_pin.center())
# self.add_via_center(layers=self.m1_stack,
# offset=out_offset)
# # PMOS1 to mid-drain to NMOS2 drain
# self.add_path("m2",
# [top_pin_offset, mid1_offset, out_offset,
# mid2_offset, bottom_pin_offset])
# This routes on M1
# Midpoints of the L routes goes vertical first then horizontal
mid1_offset = vector(top_pin_offset.x, out_offset.y)
# Midpoints of the L routes goes horizontal first then vertical
mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
# Non-preferred active contacts
self.add_via_center(layers=self.m1_stack,
directions=("V", "H"),
offset=pmos_pin.center())
# Non-preferred active contacts
self.add_via_center(layers=self.m1_stack,
directions=("V", "H"),
offset=nmos_pin.center())
self.add_via_center(layers=self.m1_stack,
offset=out_offset)
self.add_path("m1",
[top_pin_offset, mid1_offset, out_offset])
# Route in two segments to have the width rule
self.add_path("m1",
[bottom_pin_offset, mid2_offset + vector(0.5 * self.m1_width, 0)],
width=nmos_pin.height())
self.add_path("m1",
[mid2_offset, out_offset])
# PMOS1 to mid-drain to NMOS2 drain
self.add_path("m2",
[top_pin_offset, mid1_offset, out_offset,
mid2_offset, bottom_pin_offset])
# This extends the output to the edge of the cell
self.add_layout_pin_rect_center(text="Z",
layer="m1",

View File

@ -191,8 +191,10 @@ class pnand3(pgate.pgate):
def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """
self.add_nwell_contact(self.pmos, self.pmos3_pos)
self.add_pwell_contact(self.nmos_ns, self.nmos3_pos)
self.add_nwell_contact(self.pmos,
self.pmos3_pos + vector(self.m1_pitch, 0))
self.add_pwell_contact(self.nmos_ns,
self.nmos3_pos + vector(self.m1_pitch, 0))
def connect_rails(self):
""" Connect the nmos and pmos to its respective power rails """
@ -221,7 +223,7 @@ class pnand3(pgate.pgate):
self.nmos3_inst,
self.inputC_yoffset,
"C",
position="left")
position="right")
# FIXME: constant hack
if OPTS.tech_name == "s8":
@ -236,6 +238,7 @@ class pnand3(pgate.pgate):
def route_output(self):
""" Route the Z output """
# PMOS1 drain
pmos1_pin = self.pmos1_inst.get_pin("D")
# PMOS3 drain
@ -243,29 +246,56 @@ class pnand3(pgate.pgate):
# NMOS3 drain
nmos3_pin = self.nmos3_inst.get_pin("D")
# Go up to metal2 for ease on all output pins
self.add_via_center(layers=self.m1_stack,
offset=pmos1_pin.center(),
directions=("V", "V"))
self.add_via_center(layers=self.m1_stack,
offset=pmos3_pin.center(),
directions=("V", "V"))
self.add_via_center(layers=self.m1_stack,
offset=nmos3_pin.center(),
directions=("V", "V"))
# midpoint for routing
mid_offset = vector(nmos3_pin.cx() + self.m1_pitch,
self.inputA_yoffset)
# Aligned with the well taps
out_offset = vector(self.nwell_contact.cx(),
self.inputA_yoffset)
# PMOS3 and NMOS3 are drain aligned
self.add_path("m1", [pmos3_pin.center(), nmos3_pin.center()])
# Route in the A input track (top track)
mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset)
self.add_path("m1", [pmos1_pin.center(), mid_offset, nmos3_pin.uc()])
# Go up to metal2 for ease on all output pins
# self.add_via_center(layers=self.m1_stack,
# offset=pmos1_pin.center(),
# directions=("V", "V"))
# self.add_via_center(layers=self.m1_stack,
# offset=pmos3_pin.center(),
# directions=("V", "V"))
# self.add_via_center(layers=self.m1_stack,
# offset=nmos3_pin.center(),
# directions=("V", "V"))
# # Route in the A input track (top track)
# mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset)
# self.add_path("m1", [pmos1_pin.center(), mid_offset, nmos3_pin.uc()])
# This extends the output to the edge of the cell
self.add_via_center(layers=self.m1_stack,
offset=mid_offset)
# self.add_via_center(layers=self.m1_stack,
# offset=mid_offset)
top_left_pin_offset = pmos1_pin.center()
top_right_pin_offset = pmos3_pin.center()
bottom_pin_offset = nmos3_pin.center()
# PMOS1 to output
self.add_path("m1", [top_left_pin_offset,
vector(top_left_pin_offset.x, out_offset.y),
out_offset])
# PMOS3 to output
self.add_path("m1", [top_right_pin_offset,
vector(top_right_pin_offset.x, mid_offset.y),
mid_offset])
# NMOS3 to output
mid2_offset = vector(mid_offset.x, bottom_pin_offset.y)
self.add_path("m1",
[bottom_pin_offset, mid2_offset],
width=nmos3_pin.height())
mid3_offset = vector(mid_offset.x, nmos3_pin.by())
self.add_path("m1", [mid3_offset, mid_offset])
self.add_layout_pin_rect_center(text="Z",
layer="m1",
offset=mid_offset,
offset=out_offset,
width=contact.m1_via.first_layer_width,
height=contact.m1_via.first_layer_height)

View File

@ -471,13 +471,13 @@ class ptx(design.design):
"""Returns an object representing the parameters for delay in tau units."""
# FIXME: Using the same definition as the pinv.py.
parasitic_delay = 1
size = self.mults*self.tx_width/drc("minwidth_tx")
return logical_effort.logical_effort(self.name,
size,
self.input_load(),
cout,
parasitic_delay)
parasitic_delay = 1
size = self.mults * self.tx_width / drc("minwidth_tx")
return logical_effort.logical_effort(self.name,
size,
self.input_load(),
cout,
parasitic_delay)
def input_load(self):
"""
@ -485,7 +485,7 @@ class ptx(design.design):
"""
# FIXME: this will be applied for the loads of the drain/source
return self.mults*self.tx_width/drc("minwidth_tx")
return self.mults * self.tx_width / drc("minwidth_tx")
def add_diff_contact(self, label, pos):
contact=self.add_via_center(layers=self.active_stack,
@ -496,14 +496,25 @@ class ptx(design.design):
well_type=self.well_type)
if hasattr(self, "li_stack"):
self.add_via_center(layers=self.li_stack,
offset=pos)
contact=self.add_via_center(layers=self.li_stack,
offset=pos,
directions=("V", "V"))
# contact_area = contact.mod.second_layer_width * contact.mod.second_layer_height
# min_area = drc("minarea_m1")
# width = contact.mod.second_layer_width
# if contact_area < min_area:
# height = min_area / width
# else:
# height = contact.mod.second_layer_height
width = contact.mod.second_layer_width
height = contact.mod.second_layer_height
self.add_layout_pin_rect_center(text=label,
layer="m1",
offset=pos,
width=contact.mod.second_layer_width,
height=contact.mod.second_layer_height)
width=width,
height=height)
return(contact)
def get_cin(self):