mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-09-08 04:11:47 +02:00
Merge branch 'tech_migration' into dev
This commit is contained in:
@@ -46,7 +46,8 @@ class pgate(design.design):
|
||||
# This is the space from a S/D contact to the supply rail
|
||||
contact_to_vdd_rail_space = 0.5 * self.m1_width + self.m1_space
|
||||
# This is a poly-to-poly of a flipped cell
|
||||
poly_to_poly_gate_space = self.poly_extend_active + self.poly_space
|
||||
poly_to_poly_gate_space = self.poly_extend_active + 0.5 * self.poly_space
|
||||
|
||||
self.top_bottom_space = max(contact_to_vdd_rail_space,
|
||||
poly_to_poly_gate_space)
|
||||
|
||||
|
||||
+24
-18
@@ -9,7 +9,7 @@ import debug
|
||||
import pgate
|
||||
from vector import vector
|
||||
from sram_factory import factory
|
||||
|
||||
from tech import layer
|
||||
|
||||
class pinvbuf(pgate.pgate):
|
||||
"""
|
||||
@@ -111,33 +111,45 @@ class pinvbuf(pgate.pgate):
|
||||
mirror="MX")
|
||||
|
||||
def route_wires(self):
|
||||
if "li" in layer:
|
||||
route_stack = self.li_stack
|
||||
else:
|
||||
route_stack = self.m1_stack
|
||||
|
||||
# inv1 Z to inv2 A
|
||||
z1_pin = self.inv1_inst.get_pin("Z")
|
||||
a2_pin = self.inv2_inst.get_pin("A")
|
||||
mid_point = vector(z1_pin.cx(), a2_pin.cy())
|
||||
self.add_path("m1", [z1_pin.center(), mid_point, a2_pin.center()])
|
||||
self.add_path(z1_pin.layer, [z1_pin.center(), mid_point, a2_pin.center()])
|
||||
self.add_via_stack_center(from_layer=z1_pin.layer,
|
||||
to_layer=a2_pin.layer,
|
||||
offset=a2_pin.center())
|
||||
|
||||
# inv2 Z to inv3 A
|
||||
z2_pin = self.inv2_inst.get_pin("Z")
|
||||
a3_pin = self.inv3_inst.get_pin("A")
|
||||
mid_point = vector(z2_pin.cx(), a3_pin.cy())
|
||||
self.add_path("m1", [z2_pin.center(), mid_point, a3_pin.center()])
|
||||
self.add_path(z2_pin.layer, [z2_pin.center(), mid_point, a3_pin.center()])
|
||||
self.add_via_stack_center(from_layer=z2_pin.layer,
|
||||
to_layer=a3_pin.layer,
|
||||
offset=a3_pin.center())
|
||||
|
||||
# inv1 Z to inv4 A (up and over)
|
||||
z1_pin = self.inv1_inst.get_pin("Z")
|
||||
a4_pin = self.inv4_inst.get_pin("A")
|
||||
mid_point = vector(z1_pin.cx(), a4_pin.cy())
|
||||
self.add_wire(self.m1_stack,
|
||||
self.add_wire(route_stack,
|
||||
[z1_pin.center(), mid_point, a4_pin.center()])
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=z1_pin.center())
|
||||
self.add_via_stack_center(from_layer=z1_pin.layer,
|
||||
to_layer=route_stack[2],
|
||||
offset=z1_pin.center())
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
||||
# Continous vdd rail along with label.
|
||||
vdd_pin = self.inv1_inst.get_pin("vdd")
|
||||
self.add_layout_pin(text="vdd",
|
||||
layer="m1",
|
||||
layer=vdd_pin.layer,
|
||||
offset=vdd_pin.ll().scale(0, 1),
|
||||
width=self.width,
|
||||
height=vdd_pin.height())
|
||||
@@ -145,7 +157,7 @@ class pinvbuf(pgate.pgate):
|
||||
# Continous vdd rail along with label.
|
||||
gnd_pin = self.inv4_inst.get_pin("gnd")
|
||||
self.add_layout_pin(text="gnd",
|
||||
layer="m1",
|
||||
layer=gnd_pin.layer,
|
||||
offset=gnd_pin.ll().scale(0, 1),
|
||||
width=self.width,
|
||||
height=gnd_pin.height())
|
||||
@@ -153,31 +165,25 @@ class pinvbuf(pgate.pgate):
|
||||
# Continous gnd rail along with label.
|
||||
gnd_pin = self.inv1_inst.get_pin("gnd")
|
||||
self.add_layout_pin(text="gnd",
|
||||
layer="m1",
|
||||
layer=gnd_pin.layer,
|
||||
offset=gnd_pin.ll().scale(0, 1),
|
||||
width=self.width,
|
||||
height=vdd_pin.height())
|
||||
|
||||
z_pin = self.inv4_inst.get_pin("Z")
|
||||
self.add_layout_pin_rect_center(text="Z",
|
||||
layer="m2",
|
||||
layer=z_pin.layer,
|
||||
offset=z_pin.center())
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=z_pin.center())
|
||||
|
||||
zb_pin = self.inv3_inst.get_pin("Z")
|
||||
self.add_layout_pin_rect_center(text="Zb",
|
||||
layer="m2",
|
||||
layer=zb_pin.layer,
|
||||
offset=zb_pin.center())
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=zb_pin.center())
|
||||
|
||||
a_pin = self.inv1_inst.get_pin("A")
|
||||
self.add_layout_pin_rect_center(text="A",
|
||||
layer="m2",
|
||||
layer=a_pin.layer,
|
||||
offset=a_pin.center())
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=a_pin.center())
|
||||
|
||||
def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False):
|
||||
"""Get the stage efforts of the clk -> clk_buf path"""
|
||||
|
||||
@@ -177,9 +177,9 @@ class pnand2(pgate.pgate):
|
||||
|
||||
|
||||
# Top of NMOS drain
|
||||
nmos_pin = self.nmos2_inst.get_pin("D")
|
||||
bottom_pin_offset = nmos_pin.uy()
|
||||
self.inputA_yoffset = bottom_pin_offset + self.m1_pitch
|
||||
bottom_pin = self.nmos2_inst.get_pin("D")
|
||||
self.inputA_yoffset = max(bottom_pin.uy() + self.m1_pitch,
|
||||
self.nmos2_inst.uy() + self.poly_to_active)
|
||||
|
||||
self.inputB_yoffset = self.inputA_yoffset + self.m3_pitch
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from vector import vector
|
||||
import logical_effort
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
import contact
|
||||
|
||||
class pnand3(pgate.pgate):
|
||||
"""
|
||||
@@ -209,13 +209,21 @@ class pnand3(pgate.pgate):
|
||||
def route_inputs(self):
|
||||
""" Route the A and B and C inputs """
|
||||
|
||||
# We can use this pitch because the contacts and overlap won't be adjacent
|
||||
non_contact_pitch = 0.5 * self.m1_width + self.m1_space + 0.5 * contact.poly_contact.second_layer_height
|
||||
pmos_drain_bottom = self.pmos1_inst.get_pin("D").by()
|
||||
self.output_yoffset = pmos_drain_bottom - 0.5 * self.route_layer_width - self.route_layer_space
|
||||
|
||||
# This is a more compact offset, but the bottom one works better in the decoders to "center" the pins
|
||||
# in the height of the gates
|
||||
self.inputA_yoffset = self.output_yoffset - 0.5 * self.route_layer_width - self.route_layer_space
|
||||
# self.inputA_yoffset = self.output_yoffset - self.m1_pitch
|
||||
bottom_pin = self.nmos1_inst.get_pin("D")
|
||||
# active contact metal to poly contact metal spacing
|
||||
active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * contact.poly_contact.second_layer_height
|
||||
# active diffusion to poly contact spacing
|
||||
# doesn't use nmos uy because that is calculated using offset + poly height
|
||||
active_to_poly_contact = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height \
|
||||
+ self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
|
||||
|
||||
self.inputA_yoffset = max(active_contact_to_poly_contact,
|
||||
active_to_poly_contact)
|
||||
self.route_input_gate(self.pmos1_inst,
|
||||
self.nmos1_inst,
|
||||
self.inputA_yoffset,
|
||||
@@ -223,14 +231,14 @@ class pnand3(pgate.pgate):
|
||||
position="left")
|
||||
|
||||
# Put B right on the well line
|
||||
self.inputB_yoffset = self.inputA_yoffset - self.m1_pitch
|
||||
self.inputB_yoffset = self.inputA_yoffset + non_contact_pitch
|
||||
self.route_input_gate(self.pmos2_inst,
|
||||
self.nmos2_inst,
|
||||
self.inputB_yoffset,
|
||||
"B",
|
||||
position="center")
|
||||
|
||||
self.inputC_yoffset = self.inputB_yoffset - self.m1_pitch
|
||||
self.inputC_yoffset = self.inputB_yoffset + non_contact_pitch
|
||||
self.route_input_gate(self.pmos3_inst,
|
||||
self.nmos3_inst,
|
||||
self.inputC_yoffset,
|
||||
|
||||
@@ -149,13 +149,9 @@ class precharge(design.design):
|
||||
# Compute the other pmos2 location,
|
||||
# but determining offset to overlap the source and drain pins
|
||||
overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
|
||||
# This is how much the contact is placed inside the ptx active
|
||||
contact_xdiff = self.pmos.get_pin("S").lx()
|
||||
|
||||
# adds the lower pmos to layout
|
||||
bl_xoffset = self.bitcell_bl_pin.lx()
|
||||
self.lower_pmos_position = vector(max(bl_xoffset - contact_xdiff,
|
||||
self.nwell_enclose_active),
|
||||
self.lower_pmos_position = vector(self.well_enclose_active + 0.5 * self.m1_width,
|
||||
self.initial_yoffset)
|
||||
self.lower_pmos_inst.place(self.lower_pmos_position)
|
||||
|
||||
@@ -218,7 +214,7 @@ class precharge(design.design):
|
||||
|
||||
# adds the contact from active to metal1
|
||||
offset_height = self.upper_pmos1_inst.uy() + \
|
||||
0.5 * contact.active_contact.height + \
|
||||
contact.active_contact.height + \
|
||||
self.nwell_extend_active
|
||||
self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) + \
|
||||
vector(0, offset_height)
|
||||
|
||||
+3
-16
@@ -205,28 +205,15 @@ class ptx(design.design):
|
||||
# Poly height must include poly extension over active
|
||||
self.poly_height = self.tx_width + 2 * self.poly_extend_active
|
||||
|
||||
# The active offset is due to the well extension
|
||||
if "pwell" in layer:
|
||||
pwell_enclose_active = drc("pwell_enclose_active")
|
||||
else:
|
||||
pwell_enclose_active = 0
|
||||
if "nwell" in layer:
|
||||
nwell_enclose_active = drc("nwell_enclose_active")
|
||||
else:
|
||||
nwell_enclose_active = 0
|
||||
# Use the max of either so that the poly gates will align properly
|
||||
well_enclose_active = max(pwell_enclose_active,
|
||||
nwell_enclose_active)
|
||||
self.active_offset = vector([well_enclose_active] * 2)
|
||||
self.active_offset = vector([self.well_enclose_active] * 2)
|
||||
|
||||
# Well enclosure of active, ensure minwidth as well
|
||||
well_name = "{}well".format(self.well_type)
|
||||
if well_name in layer:
|
||||
well_width_rule = drc("minwidth_" + well_name)
|
||||
well_enclose_active = drc(well_name + "_enclose_active")
|
||||
self.well_width = max(self.active_width + 2 * well_enclose_active,
|
||||
self.well_width = max(self.active_width + 2 * self.well_enclose_active,
|
||||
well_width_rule)
|
||||
self.well_height = max(self.active_height + 2 * well_enclose_active,
|
||||
self.well_height = max(self.active_height + 2 * self.well_enclose_active,
|
||||
well_width_rule)
|
||||
# We are going to shift the 0,0, so include that in the width and height
|
||||
self.height = self.well_height - self.active_offset.y
|
||||
|
||||
Reference in New Issue
Block a user