mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-09-02 02:57:53 +02:00
merge local with dev
This commit is contained in:
+17
-9
@@ -15,6 +15,7 @@ from globals import OPTS
|
||||
from utils import round_to_grid
|
||||
import logical_effort
|
||||
from sram_factory import factory
|
||||
from errors import drc_error
|
||||
|
||||
|
||||
class pinv(pgate.pgate):
|
||||
@@ -108,11 +109,14 @@ class pinv(pgate.pgate):
|
||||
# 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.poly_extend_active + self.poly_space)
|
||||
total_height = tx_height + min_channel + 2 * self.top_bottom_space
|
||||
|
||||
debug.check(self.height > total_height,
|
||||
"Cell height {0} too small for simple min height {1}.".format(self.height,
|
||||
total_height))
|
||||
total_height = tx_height + min_channel + 2 * self.top_bottom_space
|
||||
# debug.check(self.height > total_height,
|
||||
# "Cell height {0} too small for simple min height {1}.".format(self.height,
|
||||
# total_height))
|
||||
if total_height > self.height:
|
||||
msg = "Cell height {0} too small for simple min height {1}.".format(self.height, total_height)
|
||||
raise drc_error(msg)
|
||||
|
||||
# Determine the height left to the transistors to determine
|
||||
# the number of fingers
|
||||
@@ -144,12 +148,16 @@ class pinv(pgate.pgate):
|
||||
# with LVS property mismatch errors when fingers are not a grid
|
||||
# length and get rounded in the offset geometry.
|
||||
self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults)
|
||||
debug.check(self.nmos_width >= drc("minwidth_tx"),
|
||||
"Cannot finger NMOS transistors to fit cell height.")
|
||||
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
|
||||
debug.check(self.pmos_width >= drc("minwidth_tx"),
|
||||
"Cannot finger PMOS transistors to fit cell height.")
|
||||
# debug.check(self.nmos_width >= drc("minwidth_tx"),
|
||||
# "Cannot finger NMOS transistors to fit cell height.")
|
||||
if self.nmos_width < drc("minwidth_tx"):
|
||||
raise drc_error("Cannot finger NMOS transistors to fit cell height.")
|
||||
|
||||
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
|
||||
#debug.check(self.pmos_width >= drc("minwidth_tx"),
|
||||
# "Cannot finger PMOS transistors to fit cell height.")
|
||||
if self.pmos_width < drc("minwidth_tx"):
|
||||
raise drc_error("Cannot finger NMOS transistors to fit cell height.")
|
||||
|
||||
def add_ptx(self):
|
||||
""" Create the PMOS and NMOS transistors. """
|
||||
|
||||
+43
-23
@@ -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",
|
||||
|
||||
+57
-23
@@ -12,6 +12,7 @@ from tech import drc, parameter, spice
|
||||
from vector import vector
|
||||
import logical_effort
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
class pnand3(pgate.pgate):
|
||||
@@ -190,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 """
|
||||
@@ -220,18 +223,22 @@ class pnand3(pgate.pgate):
|
||||
self.nmos3_inst,
|
||||
self.inputC_yoffset,
|
||||
"C",
|
||||
position="center")
|
||||
position="right")
|
||||
|
||||
# FIXME: constant hack
|
||||
self.inputA_yoffset = self.inputB_yoffset + 1.12 * m1_pitch
|
||||
if OPTS.tech_name == "s8":
|
||||
self.inputA_yoffset = self.inputB_yoffset + 1.15 * m1_pitch
|
||||
else:
|
||||
self.inputA_yoffset = self.inputB_yoffset + 1.12 * m1_pitch
|
||||
self.route_input_gate(self.pmos1_inst,
|
||||
self.nmos1_inst,
|
||||
self.inputA_yoffset,
|
||||
"A",
|
||||
position="center")
|
||||
position="left")
|
||||
|
||||
def route_output(self):
|
||||
""" Route the Z output """
|
||||
|
||||
# PMOS1 drain
|
||||
pmos1_pin = self.pmos1_inst.get_pin("D")
|
||||
# PMOS3 drain
|
||||
@@ -239,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("m2", [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("m2", [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)
|
||||
|
||||
|
||||
+25
-17
@@ -107,10 +107,7 @@ class ptx(design.design):
|
||||
# be decided in the layout later.
|
||||
area_sd = 2.5 * self.poly_width * self.tx_width
|
||||
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
|
||||
|
||||
|
||||
if OPTS.tech_name == None:
|
||||
print("here {0}".format(self.name))
|
||||
if OPTS.tech_name == "s8":
|
||||
# s8 technology is in microns
|
||||
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
||||
self.mults,
|
||||
@@ -474,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):
|
||||
"""
|
||||
@@ -488,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,
|
||||
@@ -499,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):
|
||||
|
||||
Reference in New Issue
Block a user