mirror of https://github.com/VLSIDA/OpenRAM.git
Move nmos gate to the top of the ptx.
This commit is contained in:
parent
45ae8c7315
commit
8df46abb30
|
|
@ -22,7 +22,7 @@ class pinv(design.design):
|
||||||
|
|
||||||
unique_id = 1
|
unique_id = 1
|
||||||
|
|
||||||
def __init__(self, size=1, beta=parameter["pinv_beta"], height=bitcell.height, route_output=True):
|
def __init__(self, size=1, beta=parameter["beta"], height=bitcell.height, route_output=True):
|
||||||
# We need to keep unique names because outputting to GDSII
|
# We need to keep unique names because outputting to GDSII
|
||||||
# will use the last record with a given name. I.e., you will
|
# will use the last record with a given name. I.e., you will
|
||||||
# over-write a design in GDS if one has and the other doesn't
|
# over-write a design in GDS if one has and the other doesn't
|
||||||
|
|
@ -46,11 +46,11 @@ class pinv(design.design):
|
||||||
#self.DRC_LVS()
|
#self.DRC_LVS()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
"""Adds pins for spice netlist"""
|
""" Adds pins for spice netlist """
|
||||||
self.add_pin_list(["A", "Z", "vdd", "gnd"])
|
self.add_pin_list(["A", "Z", "vdd", "gnd"])
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
"""Calls all functions related to the generation of the layout"""
|
""" Calls all functions related to the generation of the layout """
|
||||||
|
|
||||||
# These aren't for instantiating, but we use them to get the dimensions
|
# These aren't for instantiating, but we use them to get the dimensions
|
||||||
self.poly_contact = contact.contact(("poly", "contact", "metal1"))
|
self.poly_contact = contact.contact(("poly", "contact", "metal1"))
|
||||||
|
|
@ -61,15 +61,7 @@ class pinv(design.design):
|
||||||
self.setup_layout_constants()
|
self.setup_layout_constants()
|
||||||
self.add_supply_rails()
|
self.add_supply_rails()
|
||||||
self.add_ptx()
|
self.add_ptx()
|
||||||
|
|
||||||
# These aren't for instantiating, but we use them to get the dimensions
|
|
||||||
# self.nwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"),
|
|
||||||
# dimensions=(1, self.pmos.num_contacts))
|
|
||||||
# self.pwell_contact = contact.contact(layer_stack=("active", "contact", "metal1"),
|
|
||||||
# dimensions=(1, self.nmos.num_contacts))
|
|
||||||
|
|
||||||
self.extend_wells()
|
self.extend_wells()
|
||||||
#self.extend_active()
|
|
||||||
self.add_well_contacts()
|
self.add_well_contacts()
|
||||||
self.connect_rails()
|
self.connect_rails()
|
||||||
self.route_input_gate()
|
self.route_input_gate()
|
||||||
|
|
@ -142,8 +134,6 @@ class pinv(design.design):
|
||||||
|
|
||||||
# This will help with the wells and the input/output placement
|
# This will help with the wells and the input/output placement
|
||||||
self.middle_position = vector(0,0.5*self.height)
|
self.middle_position = vector(0,0.5*self.height)
|
||||||
# This will balance the PMOS and NMOS size, roughly.
|
|
||||||
#self.middle_position = vector(0,1.0/(self.beta+1)*self.height)
|
|
||||||
|
|
||||||
|
|
||||||
def create_ptx(self):
|
def create_ptx(self):
|
||||||
|
|
@ -181,18 +171,18 @@ class pinv(design.design):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# place PMOS so it is half a poly spacing down from the top
|
# place PMOS so it is half a poly spacing down from the top
|
||||||
self.pmos_pos = self.pmos.active_offset.scale(1,0) + vector(0, self.height-self.pmos.active_height-self.top_bottom_cell_space)
|
self.pmos_pos = self.pmos.active_offset.scale(1,0) \
|
||||||
|
+ vector(0, self.height-self.pmos.active_height-self.top_bottom_cell_space)
|
||||||
self.pmos_inst=self.add_inst(name="pinv_pmos",
|
self.pmos_inst=self.add_inst(name="pinv_pmos",
|
||||||
mod=self.pmos,
|
mod=self.pmos,
|
||||||
offset=self.pmos_pos)
|
offset=self.pmos_pos)
|
||||||
self.connect_inst(["Z", "A", "vdd", "vdd"])
|
self.connect_inst(["Z", "A", "vdd", "vdd"])
|
||||||
|
|
||||||
# place NMOS so that it is half a poly spacing up from the bottom
|
# place NMOS so that it is half a poly spacing up from the bottom
|
||||||
self.nmos_pos = self.nmos.active_offset.scale(1,0) + vector(0,self.nmos.active_height+self.top_bottom_cell_space)
|
self.nmos_pos = self.nmos.active_offset.scale(1,0) + vector(0,self.top_bottom_cell_space)
|
||||||
self.nmos_inst=self.add_inst(name="pinv_nmos",
|
self.nmos_inst=self.add_inst(name="pinv_nmos",
|
||||||
mod=self.nmos,
|
mod=self.nmos,
|
||||||
offset=self.nmos_pos,
|
offset=self.nmos_pos)
|
||||||
mirror="MX")
|
|
||||||
self.connect_inst(["Z", "A", "gnd", "gnd"])
|
self.connect_inst(["Z", "A", "gnd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -220,50 +210,9 @@ class pinv(design.design):
|
||||||
width=self.well_width,
|
width=self.well_width,
|
||||||
height=self.middle_position.y)
|
height=self.middle_position.y)
|
||||||
|
|
||||||
# def extend_active(self):
|
|
||||||
# """Extends the active area for n/p mos for the addition of the n/p well taps"""
|
|
||||||
# # calculates the new active width that includes the well_taps
|
|
||||||
# self.active_width = self.pmos.active_width \
|
|
||||||
# + drc["active_to_body_active"] \
|
|
||||||
# + self.pmos.active_contact.width
|
|
||||||
|
|
||||||
# # Calculates the coordinates of the bottom left corner of active area
|
|
||||||
# # of the pmos
|
|
||||||
# offset = self.pmos_position + self.pmos.active_position
|
|
||||||
# self.add_rect(layer="active",
|
|
||||||
# offset=offset,
|
|
||||||
# width=self.active_width,
|
|
||||||
# height=self.pmos.active_height)
|
|
||||||
|
|
||||||
# # Determines where the active of the well portion starts to add the
|
|
||||||
# # implant
|
|
||||||
# offset = offset + vector(self.pmos.active_width,0)
|
|
||||||
# implant_width = self.active_width - self.pmos.active_width
|
|
||||||
# self.add_rect(layer="nimplant",
|
|
||||||
# offset=offset,
|
|
||||||
# width=implant_width,
|
|
||||||
# height=self.pmos.active_height)
|
|
||||||
|
|
||||||
# # Calculates the coordinates of the bottom left corner of active area
|
|
||||||
# # of the nmos
|
|
||||||
# offset = self.nmos_position + self.nmos.active_position
|
|
||||||
# self.add_rect(layer="active",
|
|
||||||
# offset=offset,
|
|
||||||
# width=self.active_width,
|
|
||||||
# height=self.nmos.active_height)
|
|
||||||
|
|
||||||
# # Determines where the active of the well portion starts to add the
|
|
||||||
# # implant
|
|
||||||
# offset = offset + vector(self.pmos.active_width,0)
|
|
||||||
# implant_width = self.active_width - self.nmos.active_width
|
|
||||||
# self.add_rect(layer="pimplant",
|
|
||||||
# offset=offset,
|
|
||||||
# width=implant_width,
|
|
||||||
# height=self.nmos.active_height)
|
|
||||||
|
|
||||||
|
|
||||||
def route_input_gate(self):
|
def route_input_gate(self):
|
||||||
"""Routes the input gate to the left side of the cell for access"""
|
""" Route the input gate to the left side of the cell for access """
|
||||||
nmos_gate_pin = self.nmos_inst.get_pin("G")
|
nmos_gate_pin = self.nmos_inst.get_pin("G")
|
||||||
pmos_gate_pin = self.pmos_inst.get_pin("G")
|
pmos_gate_pin = self.pmos_inst.get_pin("G")
|
||||||
|
|
||||||
|
|
@ -322,13 +271,13 @@ class pinv(design.design):
|
||||||
|
|
||||||
|
|
||||||
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 """
|
||||||
|
|
||||||
layer_stack = ("active", "contact", "metal1")
|
layer_stack = ("active", "contact", "metal1")
|
||||||
|
|
||||||
# To the right a spacing away from the nmos right active edge
|
# To the right a spacing away from the nmos right active edge
|
||||||
nwell_contact_xoffset = self.nmos_pos.x + self.nmos.active_width + drc["active_to_body_active"]
|
nwell_contact_xoffset = self.nmos_pos.x + self.nmos.active_width + drc["active_to_body_active"]
|
||||||
nwell_contact_yoffset = self.nmos_pos.y - self.nmos.active_height
|
nwell_contact_yoffset = self.nmos_pos.y
|
||||||
nwell_offset = vector(nwell_contact_xoffset, nwell_contact_yoffset)
|
nwell_offset = vector(nwell_contact_xoffset, nwell_contact_yoffset)
|
||||||
# Offset by half a contact in x and y
|
# Offset by half a contact in x and y
|
||||||
nwell_offset += vector(0.5*self.nmos.active_contact.first_layer_width,
|
nwell_offset += vector(0.5*self.nmos.active_contact.first_layer_width,
|
||||||
|
|
@ -337,7 +286,7 @@ class pinv(design.design):
|
||||||
offset=nwell_offset)
|
offset=nwell_offset)
|
||||||
self.add_path("metal1",[nwell_offset,nwell_offset.scale(1,0)])
|
self.add_path("metal1",[nwell_offset,nwell_offset.scale(1,0)])
|
||||||
# Now add the full active and implant for the PMOS
|
# Now add the full active and implant for the PMOS
|
||||||
nwell_offset = self.nmos_pos + vector(self.nmos.active_width,-self.nmos.active_height)
|
nwell_offset = self.nmos_pos + vector(self.nmos.active_width,0)
|
||||||
nwell_contact_width = drc["active_to_body_active"] + self.nmos.active_contact.width
|
nwell_contact_width = drc["active_to_body_active"] + self.nmos.active_contact.width
|
||||||
self.add_rect(layer="active",
|
self.add_rect(layer="active",
|
||||||
offset=nwell_offset,
|
offset=nwell_offset,
|
||||||
|
|
@ -400,7 +349,6 @@ class pinv(design.design):
|
||||||
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
|
||||||
|
|
||||||
def analytical_delay(self, slew, load=0.0):
|
def analytical_delay(self, slew, load=0.0):
|
||||||
from tech import spice
|
|
||||||
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
|
||||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
||||||
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
|
||||||
|
|
|
||||||
|
|
@ -164,10 +164,14 @@ class ptx(design.design):
|
||||||
|
|
||||||
# The width of the poly is from the left-most to right-most poly gate
|
# The width of the poly is from the left-most to right-most poly gate
|
||||||
poly_width = poly_positions[-1].x - poly_positions[0].x + self.poly_width
|
poly_width = poly_positions[-1].x - poly_positions[0].x + self.poly_width
|
||||||
# This can be limited by poly to active spacing or the poly extension
|
if self.tx_type == "pmos":
|
||||||
distance_below_active = self.poly_width + max(self.poly_to_active,0.5*self.poly_height)
|
# This can be limited by poly to active spacing or the poly extension
|
||||||
poly_offset = poly_positions[0] - vector(0.5*self.poly_width, distance_below_active)
|
distance_below_active = self.poly_width + max(self.poly_to_active,0.5*self.poly_height)
|
||||||
|
poly_offset = poly_positions[0] - vector(0.5*self.poly_width, distance_below_active)
|
||||||
|
else:
|
||||||
|
# This can be limited by poly to active spacing or the poly extension
|
||||||
|
distance_above_active = max(self.poly_to_active,0.5*self.poly_height)
|
||||||
|
poly_offset = poly_positions[0] + vector(-0.5*self.poly_width, distance_above_active)
|
||||||
# Remove the old pin and add the new one
|
# Remove the old pin and add the new one
|
||||||
self.remove_layout_pin("G") # only keep the main pin
|
self.remove_layout_pin("G") # only keep the main pin
|
||||||
self.add_layout_pin(text="G",
|
self.add_layout_pin(text="G",
|
||||||
|
|
@ -189,6 +193,15 @@ class ptx(design.design):
|
||||||
# This is the width of a contact to extend the ends of the pin
|
# This is the width of a contact to extend the ends of the pin
|
||||||
end_offset = vector(self.active_contact.second_layer_width/2,0)
|
end_offset = vector(self.active_contact.second_layer_width/2,0)
|
||||||
|
|
||||||
|
# drains always go to the MIDDLE of the cell, so top of NMOS, bottom of PMOS
|
||||||
|
# so reverse the directions for NMOS
|
||||||
|
if self.tx_type == "pmos":
|
||||||
|
drain_dir = 1
|
||||||
|
source_dir = -1
|
||||||
|
else:
|
||||||
|
drain_dir = -1
|
||||||
|
source_dir = 1
|
||||||
|
|
||||||
if len(source_positions)>1:
|
if len(source_positions)>1:
|
||||||
self.remove_layout_pin("S") # remove the individual connections
|
self.remove_layout_pin("S") # remove the individual connections
|
||||||
# Add each vertical segment
|
# Add each vertical segment
|
||||||
|
|
@ -282,7 +295,6 @@ class ptx(design.design):
|
||||||
# The first one will always be a source
|
# The first one will always be a source
|
||||||
source_positions = [self.contact_offset]
|
source_positions = [self.contact_offset]
|
||||||
drain_positions = []
|
drain_positions = []
|
||||||
|
|
||||||
for i in range(self.mults):
|
for i in range(self.mults):
|
||||||
if i%2:
|
if i%2:
|
||||||
# It's a source... so offset from previous drain.
|
# It's a source... so offset from previous drain.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
#!/usr/bin/env python2.7
|
||||||
|
"""
|
||||||
|
Run regression tests on a parameterized nand 2. This module doesn't
|
||||||
|
generate multi_finger 2_input nand gate. It generate only the minimum
|
||||||
|
size 2_input nand gate that is nmos_width=2*tech.drc[minwidth_tx].
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
import debug
|
||||||
|
import verify
|
||||||
|
import sys
|
||||||
|
|
||||||
|
OPTS = globals.OPTS
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 04_nand_2_test")
|
||||||
|
|
||||||
|
|
||||||
|
class pnand2_test(unittest.TestCase):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
# we will manually run lvs/drc
|
||||||
|
OPTS.check_lvsdrc = False
|
||||||
|
|
||||||
|
import pnand2
|
||||||
|
import tech
|
||||||
|
|
||||||
|
debug.info(2, "Checking 2-input nand gate")
|
||||||
|
tx = pnand2.pnand2(size=1)
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
OPTS.check_lvsdrc = True
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
||||||
|
def local_check(self, tx):
|
||||||
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
tempgds = OPTS.openram_temp + "temp.gds"
|
||||||
|
|
||||||
|
tx.sp_write(tempspice)
|
||||||
|
tx.gds_write(tempgds)
|
||||||
|
|
||||||
|
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||||
|
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||||
|
|
||||||
|
os.remove(tempspice)
|
||||||
|
os.remove(tempgds)
|
||||||
|
|
||||||
|
|
||||||
|
# instantiate a copy of the class to actually run the test
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main()
|
||||||
|
|
@ -67,7 +67,7 @@ layer["boundary"]= 239
|
||||||
#technology parameter
|
#technology parameter
|
||||||
parameter={}
|
parameter={}
|
||||||
parameter["min_tx_size"] = 0.09
|
parameter["min_tx_size"] = 0.09
|
||||||
parameter["pinv_beta"] = 3
|
parameter["beta"] = 3
|
||||||
|
|
||||||
drclvs_home=os.environ.get("DRCLVS_HOME")
|
drclvs_home=os.environ.get("DRCLVS_HOME")
|
||||||
drc={}
|
drc={}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ layer["boundary"] = 83
|
||||||
#technology parameter
|
#technology parameter
|
||||||
parameter={}
|
parameter={}
|
||||||
parameter["min_tx_size"] = 1.2
|
parameter["min_tx_size"] = 1.2
|
||||||
parameter["pinv_beta"] = 2 #for use in pinv
|
parameter["beta"] = 2
|
||||||
|
|
||||||
drclvs_home=os.environ.get("DRCLVS_HOME")
|
drclvs_home=os.environ.get("DRCLVS_HOME")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue