Nwell fixes in pgates.

Fix minor PEP8 format fixes.
Fix nwell to be 55% of cell height.
Move contact in hierarchical decoder for DRC error.
This commit is contained in:
mrg 2020-02-06 16:20:09 +00:00
parent 596302d9a9
commit f0ecf385e8
9 changed files with 31 additions and 51 deletions

View File

@ -5,18 +5,14 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from tech import drc
import debug import debug
import design import design
from math import log
from math import sqrt
from math import ceil
import math import math
import contact
from sram_factory import factory from sram_factory import factory
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
class hierarchical_decoder(design.design): class hierarchical_decoder(design.design):
""" """
Dynamically generated hierarchical decoder. Dynamically generated hierarchical decoder.
@ -34,13 +30,12 @@ class hierarchical_decoder(design.design):
self.cell_height = b.height self.cell_height = b.height
self.rows = rows self.rows = rows
self.num_inputs = math.ceil(math.log(self.rows, 2)) self.num_inputs = math.ceil(math.log(self.rows, 2))
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs) (self.no_of_pre2x4, self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
self.setup_netlist_constants() self.setup_netlist_constants()
@ -309,7 +304,6 @@ class hierarchical_decoder(design.design):
self.pre2x4_inst[num].place(base) self.pre2x4_inst[num].place(base)
def place_pre3x8(self,num): def place_pre3x8(self,num):
""" Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """ """ Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """
if (self.num_inputs == 3): if (self.num_inputs == 3):
@ -321,7 +315,6 @@ class hierarchical_decoder(design.design):
self.pre3x8_inst[num].place(offset) self.pre3x8_inst[num].place(offset)
def create_row_decoder(self): def create_row_decoder(self):
""" Create the row-decoder by placing NAND2/NAND3 and Inverters """ Create the row-decoder by placing NAND2/NAND3 and Inverters
and add the primary decoder output pins. """ and add the primary decoder output pins. """
@ -329,7 +322,6 @@ class hierarchical_decoder(design.design):
self.create_decoder_nand_array() self.create_decoder_nand_array()
self.create_decoder_inv_array() self.create_decoder_inv_array()
def create_decoder_nand_array(self): def create_decoder_nand_array(self):
""" Add a column of NAND gates for final decode """ """ Add a column of NAND gates for final decode """
@ -556,7 +548,7 @@ class hierarchical_decoder(design.design):
""" 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. """
# The vias will be placed in the center and right of the cells, respectively. # The vias will be placed in the center and right of the cells, respectively.
xoffset = self.nand_inst[0].cx() xoffset = self.nand_inst[0].rx()
for num in range(0,self.rows): for num in range(0,self.rows):
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
# The nand and inv are the same height rows... # The nand and inv are the same height rows...

View File

@ -8,12 +8,11 @@
import debug import debug
import design import design
import math import math
from tech import drc
import contact import contact
from vector import vector from vector import vector
from globals import OPTS
from sram_factory import factory from sram_factory import factory
class hierarchical_predecode(design.design): class hierarchical_predecode(design.design):
""" """
Pre 2x4 and 3x8 decoder shared code. Pre 2x4 and 3x8 decoder shared code.
@ -42,7 +41,7 @@ class hierarchical_predecode(design.design):
self.add_nand(self.number_of_inputs) self.add_nand(self.number_of_inputs)
self.add_mod(self.nand) self.add_mod(self.nand)
def add_nand(self,inputs): def add_nand(self, inputs):
""" Create the NAND for the predecode input stage """ """ Create the NAND for the predecode input stage """
if inputs==2: if inputs==2:
self.nand = factory.create(module_type="pnand2", self.nand = factory.create(module_type="pnand2",
@ -51,7 +50,7 @@ class hierarchical_predecode(design.design):
self.nand = factory.create(module_type="pnand3", self.nand = factory.create(module_type="pnand3",
height=self.cell_height) height=self.cell_height)
else: else:
debug.error("Invalid number of predecode inputs: {}".format(inputs),-1) debug.error("Invalid number of predecode inputs: {}".format(inputs), -1)
def setup_layout_constraints(self): def setup_layout_constraints(self):
@ -89,7 +88,6 @@ class hierarchical_predecode(design.design):
names=decode_names, names=decode_names,
length=self.height - 2*self.m1_width) length=self.height - 2*self.m1_width)
def create_input_inverters(self): def create_input_inverters(self):
""" Create the input inverters to invert input signals for the decode stage. """ """ Create the input inverters to invert input signals for the decode stage. """
self.in_inst = [] self.in_inst = []
@ -266,7 +264,7 @@ class hierarchical_predecode(design.design):
""" 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 # Find the x offsets for where the vias/pins should be placed
in_xoffset = self.in_inst[0].rx() in_xoffset = self.in_inst[0].rx() + self.m1_space
out_xoffset = self.inv_inst[0].lx() - self.m1_space out_xoffset = self.inv_inst[0].lx() - self.m1_space
for num in range(0,self.number_of_outputs): for num in range(0,self.number_of_outputs):
# this will result in duplicate polygons for rails, but who cares # this will result in duplicate polygons for rails, but who cares

View File

@ -11,7 +11,6 @@ import debug
from tech import layer from tech import layer
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory
class pgate(design.design): class pgate(design.design):
@ -125,17 +124,20 @@ class pgate(design.design):
height=contact.poly_contact.first_layer_width, height=contact.poly_contact.first_layer_width,
width=left_gate_offset.x - contact_offset.x) width=left_gate_offset.x - contact_offset.x)
def extend_wells(self, middle_position): def extend_wells(self):
""" Extend the n/p wells to cover whole cell """ """ Extend the n/p wells to cover whole cell """
# This should match the cells in the cell library
nwell_y_offset = 0.48 * self.height
full_height = self.height + 0.5*self.m1_width
# FIXME: float rounding problem # FIXME: float rounding problem
middle_position = middle_position.snap_to_grid()
if "nwell" in layer: if "nwell" in layer:
# Add a rail width to extend the well to the top of the rail # Add a rail width to extend the well to the top of the rail
nwell_max_offset = max(self.find_highest_layer_coords("nwell").y, nwell_max_offset = max(self.find_highest_layer_coords("nwell").y,
self.height + 0.5 * self.m1_width) full_height)
nwell_position = middle_position - vector(self.well_extend_active, 0) nwell_position = vector(0, nwell_y_offset) - vector(self.well_extend_active, 0)
nwell_height = nwell_max_offset - middle_position.y nwell_height = nwell_max_offset - nwell_y_offset
self.add_rect(layer="nwell", self.add_rect(layer="nwell",
offset=nwell_position, offset=nwell_position,
width=self.well_width, width=self.well_width,
@ -151,7 +153,7 @@ class pgate(design.design):
pwell_min_offset = min(self.find_lowest_layer_coords("pwell").y, pwell_min_offset = min(self.find_lowest_layer_coords("pwell").y,
-0.5 * self.m1_width) -0.5 * self.m1_width)
pwell_position = vector(-self.well_extend_active, pwell_min_offset) pwell_position = vector(-self.well_extend_active, pwell_min_offset)
pwell_height = middle_position.y - pwell_position.y pwell_height = nwell_y_offset - pwell_position.y
self.add_rect(layer="pwell", self.add_rect(layer="pwell",
offset=pwell_position, offset=pwell_position,
width=self.well_width, width=self.well_width,

View File

@ -54,7 +54,7 @@ class pinv(pgate.pgate):
self.setup_layout_constants() self.setup_layout_constants()
self.place_ptx() self.place_ptx()
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells()
self.route_supply_rails() self.route_supply_rails()
self.connect_rails() self.connect_rails()
self.route_input_gate(self.pmos_inst, self.route_input_gate(self.pmos_inst,
@ -154,8 +154,11 @@ class pinv(pgate.pgate):
# the width is determined the multi-finger PMOS device width plus # the width is determined the multi-finger PMOS device width plus
# the well contact width, spacing between them # the well contact width, spacing between them
# space is for power supply contact to nwell m1 spacing
self.width = self.pmos.active_offset.x + self.pmos.active_width \ self.width = self.pmos.active_offset.x + self.pmos.active_width \
+ contact.nwell_contact.width + self.active_space + 0.5 * self.nwell_enclose_active + self.active_space + contact.nwell_contact.width \
+ 0.5 * self.nwell_enclose_active \
+ self.m1_space
# This includes full enclosures on each end # This includes full enclosures on each end
self.well_width = self.width + 2*self.nwell_enclose_active self.well_width = self.width + 2*self.nwell_enclose_active
# Height is an input parameter, so it is not recomputed. # Height is an input parameter, so it is not recomputed.
@ -225,9 +228,6 @@ class pinv(pgate.pgate):
nmos_drain_pos = self.nmos_inst.get_pin("D").ul() nmos_drain_pos = self.nmos_inst.get_pin("D").ul()
self.output_pos = vector(0, 0.5 * (pmos_drain_pos.y + nmos_drain_pos.y)) self.output_pos = vector(0, 0.5 * (pmos_drain_pos.y + nmos_drain_pos.y))
# This will help with the wells
self.well_pos = self.output_pos
def route_outputs(self): def route_outputs(self):
""" """
Route the output (drains) together. Route the output (drains) together.

View File

@ -53,7 +53,7 @@ class pnand2(pgate.pgate):
self.place_ptx() self.place_ptx()
self.connect_rails() self.connect_rails()
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells()
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
@ -110,7 +110,7 @@ class pnand2(pgate.pgate):
extra_contact_space = max(-self.nmos.get_pin("D").by(), 0) extra_contact_space = max(-self.nmos.get_pin("D").by(), 0)
# This is a poly-to-poly of a flipped cell # This is a poly-to-poly of a flipped cell
self.top_bottom_space = max(0.5 * self.m1_width + self.m1_space + extra_contact_space, self.top_bottom_space = max(0.5 * self.m1_width + self.m1_space + extra_contact_space,
self.poly_extend_active, self.poly_space) self.poly_extend_active + self.poly_space)
def route_supply_rails(self): def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """ """ Add vdd/gnd rails to the top and bottom. """
@ -170,9 +170,6 @@ class pnand2(pgate.pgate):
self.output_pos = vector(0, self.output_pos = vector(0,
0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos.active_height)) 0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos.active_height))
# This will help with the wells
self.well_pos = self.output_pos
def add_well_contacts(self): def add_well_contacts(self):
""" """
Add n/p well taps to the layout and connect to supplies Add n/p well taps to the layout and connect to supplies

View File

@ -61,7 +61,7 @@ class pnand3(pgate.pgate):
self.place_ptx() self.place_ptx()
self.connect_rails() self.connect_rails()
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells()
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
@ -102,10 +102,8 @@ class pnand3(pgate.pgate):
nmos = factory.create(module_type="ptx", tx_type="nmos") nmos = factory.create(module_type="ptx", tx_type="nmos")
extra_contact_space = max(-nmos.get_pin("D").by(), 0) extra_contact_space = max(-nmos.get_pin("D").by(), 0)
# This is a poly-to-poly of a flipped cell # This is a poly-to-poly of a flipped cell
self.top_bottom_space = max(0.5 * self.m1_width + self.m1_space \ self.top_bottom_space = max(0.5 * self.m1_width + self.m1_space + extra_contact_space,
+ extra_contact_space, self.poly_extend_active + self.poly_space)
self.poly_extend_active,
self.poly_space)
def route_supply_rails(self): def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """ """ Add vdd/gnd rails to the top and bottom. """
@ -179,9 +177,6 @@ class pnand3(pgate.pgate):
# This will help with the wells and the input/output placement # This will help with the wells and the input/output placement
self.output_pos = vector(0, 0.5*self.height) self.output_pos = vector(0, 0.5*self.height)
# This should be placed at the top of the NMOS well
self.well_pos = self.output_pos
def add_well_contacts(self): def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """ """ Add n/p well taps to the layout and connect to supplies """

View File

@ -52,7 +52,7 @@ class pnor2(pgate.pgate):
self.place_ptx() self.place_ptx()
self.connect_rails() self.connect_rails()
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells()
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
@ -168,9 +168,6 @@ class pnor2(pgate.pgate):
self.output_pos = vector(0, self.output_pos = vector(0,
0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos.active_height)) 0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos.active_height))
# This will help with the wells
self.well_pos = self.output_pos
def add_well_contacts(self): def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """ """ Add n/p well taps to the layout and connect to supplies """

View File

@ -8,7 +8,7 @@
import contact import contact
import design import design
import debug import debug
from tech import drc, parameter from tech import parameter
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory

View File

@ -6,14 +6,13 @@
#All rights reserved. #All rights reserved.
# #
import design import design
from tech import drc, parameter, spice from tech import parameter
import debug import debug
import math
from tech import drc
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
class pwrite_driver(design.design): class pwrite_driver(design.design):
""" """
The pwrite_driver is two tristate inverters that drive the bitlines. The pwrite_driver is two tristate inverters that drive the bitlines.