Skip to content

Commit

Permalink
Merge pull request #276 from harshkhandeparkar/prepex-glayout
Browse files Browse the repository at this point in the history
Glayout PrePEX SPICE Generation
  • Loading branch information
msaligane authored Nov 19, 2023
2 parents d7888da + 366ea3d commit 1a3607d
Show file tree
Hide file tree
Showing 15 changed files with 698 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,20 @@
from glayout.primitives.via_gen import via_stack
from glayout.primitives.guardring import tapring
from glayout.pdk.util.snap_to_grid import component_snap_to_grid
from glayout.spice import Netlist

def diff_pair_netlist(fetL: Component, fetR: Component) -> Netlist:
diff_pair_netlist = Netlist(circuit_name='DIFF_PAIR', nodes=['VP', 'VN', 'VDD1', 'VDD2', 'VTAIL', 'B'])
diff_pair_netlist.connect_netlist(
fetL.info['netlist'],
[('D', 'VDD1'), ('G', 'VP'), ('S', 'VTAIL'), ('B', 'B')]
)
diff_pair_netlist.connect_netlist(
fetR.info['netlist'],
[('D', 'VDD2'), ('G', 'VN'), ('S', 'VTAIL'), ('B', 'B')]
)

return diff_pair_netlist

@cell
def diff_pair(
Expand Down Expand Up @@ -141,7 +154,12 @@ def diff_pair(
diffpair.add_ports(PLUSgate_routeW.get_ports_list(),prefix="PLUSgateroute_W_")
diffpair.add_ports(PLUSgate_routeE.get_ports_list(),prefix="PLUSgateroute_E_")
diffpair.add_padding(layers=(pdk.get_glayer(well),), default=0)
return component_snap_to_grid(rename_ports_by_orientation(diffpair))

component = component_snap_to_grid(rename_ports_by_orientation(diffpair))

component.info['netlist'] = diff_pair_netlist(fetL, fetR)
return component




Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,42 @@
from glayout.pdk.util.snap_to_grid import component_snap_to_grid
from pydantic import validate_arguments
from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized
from glayout.spice import Netlist
from glayout.components.stacked_current_mirror import current_mirror_netlist

def diff_pair_ibias_netlist(center_diffpair: Component, current_mirror: Component, antenna_diode: Component) -> Netlist:
netlist = Netlist(
circuit_name="DIFFPAIR_CMIRROR_BIAS",
nodes=['VP', 'VN', 'VDD1', 'VDD2', 'IBIAS', 'VSS', 'B']
)

diffpair_ref = netlist.connect_netlist(
center_diffpair.info['netlist'],
[]
)

cmirror_ref = netlist.connect_netlist(
current_mirror.info['netlist'],
[('VREF', 'IBIAS')]
)

netlist.connect_subnets(
cmirror_ref,
diffpair_ref,
[('VCOPY', 'VTAIL')]
)

netlist.connect_netlist(
antenna_diode.info['netlist'],
[('D', 'VSS'), ('G', 'VSS'), ('B', 'VSS'), ('S', 'VP')]
)

netlist.connect_netlist(
antenna_diode.info['netlist'],
[('D', 'VSS'), ('G', 'VSS'), ('B', 'VSS'), ('S', 'VN')]
)

return netlist

@validate_arguments
def diff_pair_ibias(
Expand Down Expand Up @@ -145,6 +180,14 @@ def diff_pair_ibias(
viaoffset=False,
)
cmirror.add_ports(srcshort.get_ports_list(), prefix="purposegndports")
# current mirror netlist
cmirror.info['netlist'] = current_mirror_netlist(
pdk,
width=diffpair_bias[0],
length=diffpair_bias[1],
multipliers=diffpair_bias[2]
)

# add cmirror
tailcurrent_ref = diffpair_i_ << cmirror
tailcurrent_ref.movey(
Expand All @@ -158,6 +201,9 @@ def diff_pair_ibias(
purposegndPort.name = "ibias_purposegndport"
diffpair_i_.add_ports([purposegndPort])
diffpair_i_.add_ports(tailcurrent_ref.get_ports_list(), prefix="ibias_")

diffpair_i_ref = prec_ref_center(diffpair_i_)

diffpair_i_ref.info['netlist'] = diff_pair_ibias_netlist(center_diffpair_comp, cmirror, antenna_diode_comp)
return diffpair_i_ref

Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ def __add_diff_pair_and_bias(pdk: MappedPDK, toplevel_stacked: Component, half_d
diffpair_i_ref = diff_pair_ibias(pdk, half_diffpair_params, diffpair_bias, rmult, with_antenna_diode_on_diffinputs)
toplevel_stacked.add(diffpair_i_ref)
toplevel_stacked.add_ports(diffpair_i_ref.get_ports_list(),prefix="diffpair_")

toplevel_stacked.info['netlist'] = diffpair_i_ref.info['netlist']

return toplevel_stacked

@validate_arguments
Expand Down Expand Up @@ -103,11 +106,11 @@ def __route_bottom_ncomps_except_drain_nbias(pdk: MappedPDK, toplevel_stacked: C


def diff_pair_stackedcmirror(
pdk: MappedPDK,
half_diffpair_params: tuple[float, float, int],
diffpair_bias: tuple[float, float, int],
pdk: MappedPDK,
half_diffpair_params: tuple[float, float, int],
diffpair_bias: tuple[float, float, int],
half_common_source_nbias: tuple[float, float, int, int],
rmult: int,
rmult: int,
with_antenna_diode_on_diffinputs: int
) -> Component:
# create toplevel_stacked component
Expand All @@ -123,4 +126,5 @@ def diff_pair_stackedcmirror(
# route bottom ncomps except drain of nbias (still need to place common source pmos amp)
toplevel_stacked, halfmultn_drain_routeref, halfmultn_gate_routeref, _cref = __route_bottom_ncomps_except_drain_nbias(pdk, toplevel_stacked, gndpin, half_common_source_nbias[3])
toplevel_stacked.add_ports(gndpin.get_ports_list(), prefix="pin_gnd_")

return toplevel_stacked, halfmultn_drain_routeref, halfmultn_gate_routeref, _cref
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from glayout.pdk.util.snap_to_grid import component_snap_to_grid
from pydantic import validate_arguments
from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized
from glayout.spice import Netlist



Expand Down Expand Up @@ -83,6 +84,7 @@ def __create_sharedgatecomps(pdk: MappedPDK, rmult: int, half_pload: tuple[float
ytranslation_pcenter = 2 * pcenterfourunits.ymax + 5*pdk.util_max_metal_seperation()
ptop_AB = (shared_gate_comps << twomultpcomps).movey(ytranslation_pcenter)
pbottom_AB = (shared_gate_comps << twomultpcomps).movey(-1 * ytranslation_pcenter)

return shared_gate_comps, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports


Expand Down Expand Up @@ -144,10 +146,32 @@ def __route_sharedgatecomps(pdk: MappedPDK, shared_gate_comps, via_location, pto
shared_gate_comps.add_ports(mimcap_connection_ref.get_ports_list(),prefix="mimcap_connection_")
return shared_gate_comps

def differential_to_single_ended_converter_netlist(pdk: MappedPDK, half_pload: tuple[float, float, int]) -> Netlist:
return Netlist(
circuit_name="DIFF_TO_SINGLE",
nodes=['VIN', 'VOUT', 'VSS', 'VSS2'],
source_netlist=""".subckt {circuit_name} {nodes} l=1 w=1 mt=1 mb=1
XTOP1 V1 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}}
XBOT2 VOUT VIN VSS2 VSS {model} l={{l}} w={{w}} m={{mb}}
.ends {circuit_name}""",
instance_format="X{name} {nodes} {circuit_name} l={length} w={width} mt={mult_top} mb={mult_bot}",
parameters={
'model': pdk.models['pfet'],
'width': half_pload[0],
'length': half_pload[1],
'mult_top': 4 * 2,
'mult_bot': half_pload[2] * 2
}
)

def differential_to_single_ended_converter(pdk: MappedPDK, rmult: int, half_pload: tuple[float,float,int], via_xlocation) -> tuple:
clear_cache()
pmos_comps, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports = __create_sharedgatecomps(pdk, rmult,half_pload)
clear_cache()
pmos_comps = __route_sharedgatecomps(pdk, pmos_comps, via_xlocation, ptop_AB, pbottom_AB, LRplusdopedPorts, LRgatePorts, LRdrainsPorts, LRsourcesPorts, LRdummyports)

pmos_comps.info['netlist'] = differential_to_single_ended_converter_netlist(pdk, half_pload)

return pmos_comps
49 changes: 45 additions & 4 deletions openfasoc/generators/gdsfactory-gen/glayout/components/opamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,30 @@
from glayout.pdk.util.snap_to_grid import component_snap_to_grid
from pydantic import validate_arguments
from glayout.placement.two_transistor_interdigitized import two_nfet_interdigitized

from glayout.spice import Netlist

from glayout.components.opamp_twostage import opamp_twostage
from glayout.components.stacked_current_mirror import current_mirror_netlist

def opamp_output_stage_netlist(pdk: MappedPDK, output_amp_fet_ref: ComponentReference, biasParams: list) -> Netlist:
bias_netlist = current_mirror_netlist(pdk, biasParams[0], biasParams[1], biasParams[2])

output_stage_netlist = Netlist(
circuit_name="OUTPUT_STAGE",
nodes=['VDD', 'GND', 'IBIAS', 'VIN', 'VOUT']
)

output_stage_netlist.connect_netlist(
output_amp_fet_ref.info['netlist'],
[('D', 'VDD'), ('G', 'VIN'), ('B', 'GND'), ('S', 'VOUT')]
)

output_stage_netlist.connect_netlist(
bias_netlist,
[('VREF', 'IBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')]
)

return output_stage_netlist

@validate_arguments
def __add_output_stage(
Expand All @@ -30,7 +50,7 @@ def __add_output_stage(
amplifierParams: tuple[float, float, int],
biasParams: list,
rmult: int,
) -> Component:
) -> tuple[Component, Netlist]:
'''add output stage to opamp_top, args:
pdk = pdk to use
opamp_top = component to add output stage to
Expand Down Expand Up @@ -65,6 +85,7 @@ def __add_output_stage(
with_substrate_tap=False,
tie_layers=("met2","met2")
)

metal_sep = pdk.util_max_metal_seperation()
# Locate output stage relative position
# x-coordinate: Center of SW capacitor in array
Expand Down Expand Up @@ -107,9 +128,27 @@ def __add_output_stage(
bias_pin.movex(cmirror_ibias.center[0]).movey(cmirror_ibias.ports["B_gate_S"].center[1]-bias_pin.ymax-5*metal_sep)
opamp_top << straight_route(pdk, bias_pin.ports["e2"], cmirror_ibias.ports["B_gate_S"],width=1)
opamp_top.add_ports(bias_pin.get_ports_list(),prefix="pin_outputibias_")
return opamp_top

output_stage_netlist = opamp_output_stage_netlist(pdk, amp_fet_ref, biasParams)
return opamp_top, output_stage_netlist

def opamp_netlist(two_stage_netlist: Netlist, output_stage_netlist: Netlist) -> Netlist:
top_level_netlist = Netlist(
circuit_name="opamp",
nodes=['gnd', 'CSoutput', 'output', 'vdd', 'plus', 'minus', 'commonsourceibias', 'outputibias', 'diffpairibias']
)

top_level_netlist.connect_netlist(
two_stage_netlist,
[('VDD', 'vdd'), ('GND', 'gnd'), ('DIFFPAIR_BIAS', 'diffpairibias'), ('VP', 'plus'), ('VN', 'minus'), ('CS_BIAS', 'commonsourceibias'), ('VOUT', 'CSoutput')]
)

top_level_netlist.connect_netlist(
output_stage_netlist,
[('VDD', 'vdd'), ('GND', 'gnd'), ('IBIAS', 'outputibias'), ('VIN', 'CSoutput'), ('VOUT', 'output')]
)

return top_level_netlist

@cell
def opamp(
Expand Down Expand Up @@ -155,7 +194,9 @@ def opamp(
with_antenna_diode_on_diffinputs
)
# add output amplfier stage
opamp_top = __add_output_stage(pdk, opamp_top, output_stage_params, output_stage_bias, rmult)
opamp_top, output_stage_netlist = __add_output_stage(pdk, opamp_top, output_stage_params, output_stage_bias, rmult)
opamp_top.info['netlist'] = opamp_netlist(opamp_top.info['netlist'], output_stage_netlist)

# return
return rename_ports_by_orientation(component_snap_to_grid(opamp_top))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
from glayout.components.differential_to_single_ended_converter import differential_to_single_ended_converter
from glayout.components.row_csamplifier_diff_to_single_ended_converter import row_csamplifier_diff_to_single_ended_converter
from glayout.components.diff_pair_stackedcmirror import diff_pair_stackedcmirror


from glayout.spice import Netlist
from glayout.components.stacked_current_mirror import current_mirror_netlist

@validate_arguments
def __create_and_route_pins(
Expand Down Expand Up @@ -106,10 +106,13 @@ def __create_and_route_pins(


@validate_arguments
def __add_mimcap_arr(pdk: MappedPDK, opamp_top: Component, mim_cap_size, mim_cap_rows, ymin: float, n_to_p_output_route) -> Component:
def __add_mimcap_arr(pdk: MappedPDK, opamp_top: Component, mim_cap_size, mim_cap_rows, ymin: float, n_to_p_output_route) -> tuple[Component, Netlist]:
mim_cap_size = pdk.snap_to_2xgrid(mim_cap_size, return_type="float")
max_metalsep = pdk.util_max_metal_seperation()
mimcaps_ref = opamp_top << mimcap_array(pdk,mim_cap_rows,2,size=mim_cap_size,rmult=6)

mimcap_netlist = mimcaps_ref.info['netlist']

displace_fact = max(max_metalsep,pdk.get_grule("capmet")["min_separation"])
mimcaps_ref.movex(pdk.snap_to_2xgrid(opamp_top.xmax + displace_fact + mim_cap_size[0]/2))
mimcaps_ref.movey(pdk.snap_to_2xgrid(ymin + mim_cap_size[1]/2))
Expand All @@ -123,9 +126,57 @@ def __add_mimcap_arr(pdk: MappedPDK, opamp_top: Component, mim_cap_size, mim_cap
opamp_top.add_ports(mimcaps_ref.get_ports_list(),prefix="mimcap_")
# add the cs output as a port
opamp_top.add_port(name="commonsource_output_E", port=intermediate_output)
return opamp_top
return opamp_top, mimcap_netlist

def opamp_gain_stage_netlist(mimcap_netlist: Netlist, diff_cs_netlist: Netlist, cs_bias_netlist: Netlist) -> Netlist:
netlist = Netlist(
circuit_name="GAIN_STAGE",
nodes=['VIN1', 'VIN2', 'VOUT', 'VDD', 'IBIAS', 'GND']
)

diff_cs_ref = netlist.connect_netlist(
diff_cs_netlist,
[('VSS', 'VDD')]
)

netlist.connect_netlist(
cs_bias_netlist,
[('VREF', 'IBIAS'), ('VSS', 'GND'), ('VCOPY', 'VOUT')]
)

mimcap_ref = netlist.connect_netlist(mimcap_netlist, [('V2', 'VOUT')])

netlist.connect_subnets(
mimcap_ref,
diff_cs_ref,
[('V1', 'VSS2')]
)

return netlist

def opamp_twostage_netlist(input_stage_netlist: Netlist, gain_stage_netlist: Netlist) -> Netlist:
two_stage_netlist = Netlist(
circuit_name="OPAMP_TWO_STAGE",
nodes=['VDD', 'GND', 'DIFFPAIR_BIAS', 'VP', 'VN', 'CS_BIAS', 'VOUT']
)

input_stage_ref = two_stage_netlist.connect_netlist(
input_stage_netlist,
[('IBIAS', 'DIFFPAIR_BIAS'), ('VSS', 'GND'), ('B', 'GND')]
)

gain_stage_ref = two_stage_netlist.connect_netlist(
gain_stage_netlist,
[('IBIAS', 'CS_BIAS')]
)

two_stage_netlist.connect_subnets(
input_stage_ref,
gain_stage_ref,
[('VDD1', 'VIN1'), ('VDD2', 'VIN2')]
)

return two_stage_netlist

def opamp_twostage(
pdk: MappedPDK,
Expand Down Expand Up @@ -159,10 +210,22 @@ def opamp_twostage(
if half_common_source_bias[3] < 2:
raise ValueError("half_common_source_bias num multiplier must be >= 2")
opamp_top, halfmultn_drain_routeref, halfmultn_gate_routeref, _cref = diff_pair_stackedcmirror(pdk, half_diffpair_params, diffpair_bias, half_common_source_bias, rmult, with_antenna_diode_on_diffinputs)

opamp_top.info['netlist'].circuit_name = "INPUT_STAGE"

# place pmos components
pmos_comps = differential_to_single_ended_converter(pdk, rmult, half_pload, opamp_top.ports["diffpair_tl_multiplier_0_drain_N"].center[0])
clear_cache()

pmos_comps = row_csamplifier_diff_to_single_ended_converter(pdk, pmos_comps, half_common_source_params, rmult)

cs_bias_netlist = current_mirror_netlist(
pdk,
width=diffpair_bias[0],
length=diffpair_bias[1],
multipliers=diffpair_bias[2]
)

ydim_ncomps = opamp_top.ymax
pmos_comps_ref = opamp_top << pmos_comps
pmos_comps_ref.movey(round(ydim_ncomps + pmos_comps_ref.ymax+10))
Expand All @@ -174,10 +237,14 @@ def opamp_twostage(
opamp_top, n_to_p_output_route = __create_and_route_pins(pdk, opamp_top, pmos_comps_ref, halfmultn_drain_routeref, halfmultn_gate_routeref)
# place mimcaps and route
clear_cache()
opamp_top = __add_mimcap_arr(pdk, opamp_top, mim_cap_size, mim_cap_rows, pmos_comps_ref.ymin, n_to_p_output_route)
opamp_top, mimcap_netlist = __add_mimcap_arr(pdk, opamp_top, mim_cap_size, mim_cap_rows, pmos_comps_ref.ymin, n_to_p_output_route)
opamp_top.add_ports(n_to_p_output_route.get_ports_list(),"special_con_npr_")
# return
opamp_top.add_ports(_cref.get_ports_list(), prefix="gnd_route_")

pmos_comps.info['netlist'] = opamp_gain_stage_netlist(mimcap_netlist, pmos_comps.info['netlist'], cs_bias_netlist)
opamp_top.info['netlist'] = opamp_twostage_netlist(opamp_top.info['netlist'], pmos_comps.info['netlist'])

return opamp_top


Loading

0 comments on commit 1a3607d

Please sign in to comment.