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
|
||||
|
||||
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
|
||||
# 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
|
||||
|
|
@ -46,11 +46,11 @@ class pinv(design.design):
|
|||
#self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
"""Adds pins for spice netlist"""
|
||||
""" Adds pins for spice netlist """
|
||||
self.add_pin_list(["A", "Z", "vdd", "gnd"])
|
||||
|
||||
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
|
||||
self.poly_contact = contact.contact(("poly", "contact", "metal1"))
|
||||
|
|
@ -61,15 +61,7 @@ class pinv(design.design):
|
|||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
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_active()
|
||||
self.add_well_contacts()
|
||||
self.connect_rails()
|
||||
self.route_input_gate()
|
||||
|
|
@ -142,8 +134,6 @@ class pinv(design.design):
|
|||
|
||||
# This will help with the wells and the input/output placement
|
||||
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):
|
||||
|
|
@ -181,18 +171,18 @@ class pinv(design.design):
|
|||
"""
|
||||
|
||||
# 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",
|
||||
mod=self.pmos,
|
||||
offset=self.pmos_pos)
|
||||
self.connect_inst(["Z", "A", "vdd", "vdd"])
|
||||
|
||||
# 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",
|
||||
mod=self.nmos,
|
||||
offset=self.nmos_pos,
|
||||
mirror="MX")
|
||||
offset=self.nmos_pos)
|
||||
self.connect_inst(["Z", "A", "gnd", "gnd"])
|
||||
|
||||
|
||||
|
|
@ -220,50 +210,9 @@ class pinv(design.design):
|
|||
width=self.well_width,
|
||||
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):
|
||||
"""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")
|
||||
pmos_gate_pin = self.pmos_inst.get_pin("G")
|
||||
|
||||
|
|
@ -322,13 +271,13 @@ class pinv(design.design):
|
|||
|
||||
|
||||
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")
|
||||
|
||||
# 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_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)
|
||||
# Offset by half a contact in x and y
|
||||
nwell_offset += vector(0.5*self.nmos.active_contact.first_layer_width,
|
||||
|
|
@ -337,7 +286,7 @@ class pinv(design.design):
|
|||
offset=nwell_offset)
|
||||
self.add_path("metal1",[nwell_offset,nwell_offset.scale(1,0)])
|
||||
# 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
|
||||
self.add_rect(layer="active",
|
||||
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"]
|
||||
|
||||
def analytical_delay(self, slew, load=0.0):
|
||||
from tech import spice
|
||||
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
|
||||
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
|
||||
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
|
||||
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)
|
||||
|
||||
if self.tx_type == "pmos":
|
||||
# This can be limited by poly to active spacing or the poly extension
|
||||
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
|
||||
self.remove_layout_pin("G") # only keep the main pin
|
||||
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
|
||||
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:
|
||||
self.remove_layout_pin("S") # remove the individual connections
|
||||
# Add each vertical segment
|
||||
|
|
@ -282,7 +295,6 @@ class ptx(design.design):
|
|||
# The first one will always be a source
|
||||
source_positions = [self.contact_offset]
|
||||
drain_positions = []
|
||||
|
||||
for i in range(self.mults):
|
||||
if i%2:
|
||||
# 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
|
||||
parameter={}
|
||||
parameter["min_tx_size"] = 0.09
|
||||
parameter["pinv_beta"] = 3
|
||||
parameter["beta"] = 3
|
||||
|
||||
drclvs_home=os.environ.get("DRCLVS_HOME")
|
||||
drc={}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ layer["boundary"] = 83
|
|||
#technology parameter
|
||||
parameter={}
|
||||
parameter["min_tx_size"] = 1.2
|
||||
parameter["pinv_beta"] = 2 #for use in pinv
|
||||
parameter["beta"] = 2
|
||||
|
||||
drclvs_home=os.environ.get("DRCLVS_HOME")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue