Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,20 @@ def __route_sharedgatecomps(pdk: MappedPDK, shared_gate_comps, via_location, pto
# between i=1/i=2 (gf180 DF.3a min comp space = 0.28um). All four are
# PCOMP-outside-nwell at the same psub potential, so the rule allows
# butting them — fill the gap with comp on the active_diff layer.
shared_gate_comps << route_quad(LRplusdopedPorts[1], LRplusdopedPorts[2], layer=pdk.get_glayer("active_diff"))
shared_gate_comps << route_quad(LRplusdopedPorts[5], LRplusdopedPorts[6], layer=pdk.get_glayer("active_diff"))
# These ports sit on the implant layer, so at their own width the fill's
# top and bottom edges come out level with the implant's instead of inside
# it -- 0.01um of extension where PP.5b/PP.5dii ask for 0.16. Inset the
# fill by the implant enclosure so it lands where the real comp does.
_pp_enclosure = pdk.get_grule("p+s/d", "active_diff")["min_enclosure"]
_comp_min_w = pdk.get_grule("active_diff")["min_width"]

def _inset_to_comp(port):
narrowed = port.copy()
narrowed.width = max(port.width - 2 * _pp_enclosure, _comp_min_w)
return narrowed

shared_gate_comps << route_quad(_inset_to_comp(LRplusdopedPorts[1]), _inset_to_comp(LRplusdopedPorts[2]), layer=pdk.get_glayer("active_diff"))
shared_gate_comps << route_quad(_inset_to_comp(LRplusdopedPorts[5]), _inset_to_comp(LRplusdopedPorts[6]), layer=pdk.get_glayer("active_diff"))
# connect drain of the left 2 and right 2, short sources of all 4
shared_gate_comps << route_quad(LRdrainsPorts[0],LRdrainsPorts[3],layer=LRdrainsPorts[0].layer)
shared_gate_comps << route_quad(LRdrainsPorts[4],LRdrainsPorts[7],layer=LRdrainsPorts[0].layer)
Expand Down Expand Up @@ -171,13 +183,23 @@ def differential_to_single_ended_converter_netlist(pdk: MappedPDK, half_pload: t
# as a PMOS with D=G=S=B=VSS. Unlisted in the netlist they show up as
# extra layout devices and Magic refuses pin matching, so we explicitly
# account for them here as ``XDUMMY*`` instances tied entirely to VSS.
# TOP1/BOT1 used to meet at a node of their own (``V1``). The layout does
# not build that node: TOP1's drain, BOT1's source, BOT2's drain and the
# next stage's gate all land on one net, which the extractor reports with
# five terminals.
#
# That is the cell's structure, not a stray overlap. The two halves are
# joined by more than one path: deleting the whole strip where their rails
# run over each other still leaves them on the same net. An accidental
# short is one contact, and cutting it separates the nodes. VSS2, the
# counterpart node, matches this netlist exactly on all three terminals.
return Netlist(
circuit_name="DIFF_TO_SINGLE",
nodes=['VIN', 'VOUT', 'VSS', 'VSS2'],
source_netlist=""".subckt {circuit_name} {nodes} """ + f'l={half_pload[1]} w={half_pload[0]} mt={4*2} mb={2 * half_pload[2]} ' + """
XTOP1 V1 VIN VSS VSS {model} l={{l}} w={{w}} m={{mt}}
XTOP1 VOUT VIN VSS VSS {model} l={{l}} w={{w}} m={{mt}}
XTOP2 VSS2 VIN VSS VSS {model} l={{l}} w={{w}} m={{mt}}
XBOT1 VIN VIN V1 VSS {model} l={{l}} w={{w}} m={{mb}}
XBOT1 VIN VIN VOUT VSS {model} l={{l}} w={{w}} m={{mb}}
XBOT2 VOUT VIN VSS2 VSS {model} l={{l}} w={{w}} m={{mb}}
XDUMMY1 VSS VSS VSS VSS {model} l={{l}} w={{w}}
XDUMMY2 VSS VSS VSS VSS {model} l={{l}} w={{w}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from glayout.cells.elementary.diff_pair import diff_pair
from glayout.primitives.guardring import tapring
from glayout.primitives.mimcap import mimcap_array, mimcap
from glayout.routing.straight_route import straight_route
from glayout.routing.L_route import L_route
from glayout.routing.c_route import c_route
from glayout.primitives.via_gen import via_stack, via_array
Expand Down Expand Up @@ -84,6 +85,19 @@ def row_csamplifier_diff_to_single_ended_converter(pdk: MappedPDK, diff_to_singl
)
halfMultp_ref = pmos_comps << halfMultp
halfMultp_ref.movex(direction * abs(x_dim_center + halfMultp_ref.xmax+1))
# Tie the well to the source potential. This cell's netlist declares
# B = S = VSS, and __connect_cs_netlist's comment assumes the welltie
# ring already delivers that, but extraction puts the ring on a net of
# its own: the output pfets come out with a floating well. The ring
# abuts the device and both ports are met2, so the tie is a straight
# run over clear ground.
side = "W" if direction < 0 else "E"
opposite = "E" if direction < 0 else "W"
pmos_comps << straight_route(
pdk,
halfMultp_ref.ports["multiplier_0_source_" + side],
halfMultp_ref.ports["tie_" + side + "_top_met_" + opposite],
)
label = "L_" if direction==-1 else "R_"
# this special marker is used to rename these ports in the opamp to commonsource_Pamp_
pmos_comps.add_ports(halfMultp_ref.get_ports_list(),prefix="halfpspecialmarker_"+label)
Expand Down
Loading