-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Common source amp with diode connected load #354
base: main
Are you sure you want to change the base?
Changes from all commits
766fb09
5d9773c
13038c1
c4716ec
5398939
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .csamplifier_diodeconnectedload_cell import csamplifier_diodeconnectedload_cell |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
from gdsfactory.cell import cell, clear_cache | ||
from gdsfactory.component import Component, copy | ||
from gdsfactory.component_reference import ComponentReference | ||
from gdsfactory.components.rectangle import rectangle | ||
from glayout.flow.pdk.mappedpdk import MappedPDK | ||
from typing import Optional, Union | ||
from glayout.flow.primitives.fet import nmos, pmos, multiplier | ||
from glayout.flow.blocks.elementary.diff_pair import diff_pair | ||
from glayout.flow.primitives.guardring import tapring | ||
from glayout.flow.primitives.mimcap import mimcap_array, mimcap | ||
from glayout.flow.routing.L_route import L_route | ||
from glayout.flow.routing.c_route import c_route | ||
from glayout.flow.primitives.via_gen import via_stack, via_array | ||
from gdsfactory.routing.route_quad import route_quad | ||
from glayout.flow.pdk.util.comp_utils import evaluate_bbox, prec_ref_center, movex, movey, to_decimal, to_float, move, align_comp_to_port, get_padding_points_cc | ||
from glayout.flow.pdk.util.port_utils import rename_ports_by_orientation, rename_ports_by_list, add_ports_perimeter, print_ports, set_port_orientation, rename_component_ports | ||
from glayout.flow.routing.straight_route import straight_route | ||
from glayout.flow.pdk.util.snap_to_grid import component_snap_to_grid | ||
from pydantic import validate_arguments | ||
from glayout.flow.placement.two_transistor_interdigitized import two_nfet_interdigitized | ||
from glayout.flow.spice import Netlist | ||
|
||
def csamplifier_diodeconnectedload_netlist( | ||
pdk: MappedPDK, | ||
width: float, | ||
length: float, | ||
multipliers: int, | ||
n_or_p_fet: Optional[str] = 'nfet', | ||
subckt_only: Optional[bool] = False | ||
) -> Netlist: | ||
if length is None: | ||
length = pdk.get_grule('poly')['min_width'] | ||
if width is None: | ||
width = 3 | ||
mtop = multipliers if subckt_only else 1 | ||
model = pdk.models[n_or_p_fet] | ||
|
||
source_netlist = """.subckt {circuit_name} {nodes} """ + f'l={length} w={width} m={mtop} ' + """ | ||
XIN VOUT VIN VSS VB {model} l={{l}} w={{w}} m={{m}} | ||
XLOAD VDD VDD VOUT VB {model} l={{l}} w={{w}} m={{m}}""" | ||
source_netlist += "\n.ends {circuit_name}" | ||
|
||
instance_format = "X{name} {nodes} {circuit_name} l={length} w={width} m={mult}" | ||
return Netlist( | ||
circuit_name='CMIRROR', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name of the component is not cmirror right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No I am working on the common source amplifier with diode connected load. I am still working on the DRC and LVS. I will be able to update the PR soon with the new results. |
||
nodes=['VREF', 'VCOPY', 'VSS', 'VB'], | ||
source_netlist=source_netlist, | ||
instance_format=instance_format, | ||
parameters={ | ||
'model': model, | ||
'width': width, | ||
'length': length, | ||
'mult': multipliers | ||
} | ||
) | ||
|
||
#@cell | ||
def csamplifier_diodeconnectedload( | ||
pdk: MappedPDK, | ||
numcols: int = 3, | ||
device: str = 'nfet', | ||
with_dummy: Optional[bool] = True, | ||
with_substrate_tap: Optional[bool] = False, | ||
with_tie: Optional[bool] = True, | ||
tie_layers: tuple[str,str]=("met2","met1"), | ||
**kwargs | ||
)-> Component: | ||
"""An instantiable common source amplifier that returns a Component object. The common source amplifier is a two transistor structure with a gate-drain connected load. It can be instantiated with nmos. It can also be instantiated with a dummy device, a substrate tap, and a tie layer, and is centered at the origin. Transistor XIN acts as the input and transistor XD acts as the load. | ||
Args: | ||
pdk (MappedPDK): the process design kit to use | ||
numcols (int): number of columns of the interdigitized fets | ||
device (str): nfet or pfet (can only interdigitize one at a time with this option) | ||
with_dummy (bool): True places dummies on either side of the interdigitized fets | ||
with_substrate_tap (bool): boolean to decide whether to place a substrate tapring | ||
with_tie (bool): boolean to decide whether to place a tapring for tielayer | ||
tie_layers (tuple[str,str], optional): the layers to use for the tie. Defaults to ("met2","met1"). | ||
**kwargs: The keyword arguments are passed to the two_nfet_interdigitized or two_pfet_interdigitized functions and need to be valid arguments that can be accepted by the multiplier function | ||
|
||
Returns: | ||
Component: a common source diode connected load component object | ||
""" | ||
top_level = Component("current mirror") | ||
interdigitized_fets = two_nfet_interdigitized( | ||
pdk, | ||
numcols=numcols, | ||
dummy=with_dummy, | ||
with_substrate_tap=False, | ||
with_tie=False, | ||
**kwargs | ||
) | ||
top_level.add_ports(interdigitized_fets.get_ports_list(), prefix="fet_") | ||
maxmet_sep = pdk.util_max_metal_seperation() | ||
#short gate and drain of the load mosfet | ||
gatedrain_short=interdigitized_fets << c_route(pdk, interdigitized_fets.ports['A_gate_W'], interdigitized_fets.ports['B_drain_W'], extension=3*maxmet_sep, viaoffset=False) | ||
# short drain of in with source of load | ||
interdigitized_fets << straight_route(pdk, interdigitized_fets.ports['A_drain_E'], interdigitized_fets.ports['B_source_E'], extension=3*maxmet_sep, viaoffset=False) | ||
|
||
top_level << interdigitized_fets | ||
# add the tie layer | ||
if with_tie: | ||
tap_sep = max( | ||
pdk.util_max_metal_seperation(), | ||
pdk.get_grule("active_diff", "active_tap")["min_separation"], | ||
) | ||
tap_sep += pdk.get_grule("p+s/d", "active_tap")["min_enclosure"] | ||
tap_encloses = ( | ||
2 * (tap_sep + interdigitized_fets.xmax), | ||
2 * (tap_sep + interdigitized_fets.ymax), | ||
) | ||
tie_ref = top_level << tapring(pdk, enclosed_rectangle = tap_encloses, sdlayer = "p+s/d", horizontal_glayer = tie_layers[0], vertical_glayer = tie_layers[1]) | ||
top_level.add_ports(tie_ref.get_ports_list(), prefix="welltie_") | ||
try: | ||
top_level << straight_route(pdk, top_level.ports["A_0_dummy_L_gsdcon_top_met_W"],top_level.ports["welltie_W_top_met_W"],glayer2="met1") | ||
except KeyError: | ||
pass | ||
try: | ||
end_col = numcols - 1 | ||
port1 = f'B_{end_col}_dummy_R_gdscon_top_met_E' | ||
top_level << straight_route(pdk, top_level.ports[port1], top_level.ports["welltie_E_top_met_E"], glayer2="met1") | ||
except KeyError: | ||
pass | ||
|
||
# add a pwell | ||
top_level.add_padding(layers = (pdk.get_glayer("pwell"),), default = pdk.get_grule("pwell", "active_tap")["min_enclosure"], ) | ||
top_level = add_ports_perimeter(top_level, layer = pdk.get_glayer("pwell"), prefix="well_") | ||
|
||
# add the substrate tap if specified | ||
if with_substrate_tap: | ||
subtap_sep = pdk.get_grule("dnwell", "active_tap")["min_separation"] | ||
subtap_enclosure = ( | ||
2.5 * (subtap_sep + interdigitized_fets.xmax), | ||
2.5 * (subtap_sep + interdigitized_fets.ymax), | ||
) | ||
subtap_ring = top_level << tapring(pdk, enclosed_rectangle = subtap_enclosure, sdlayer = "p+s/d", horizontal_glayer = "met2", vertical_glayer = "met1") | ||
top_level.add_ports(subtap_ring.get_ports_list(), prefix="substrate_tap_") | ||
|
||
#top_level.add_ports(source_short.get_ports_list(), prefix='purposegndports') | ||
|
||
|
||
top_level.info['netlist'] = current_mirror_netlist( | ||
pdk, | ||
width=kwargs.get('width', 3), length=kwargs.get('length', 1), multipliers=numcols, | ||
n_or_p_fet=device, | ||
subckt_only=True | ||
) | ||
|
||
return top_level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to write the spice for the netlist, you can construct it using the sub-devices. Refer to
OpenFASOC/openfasoc/generators/glayout/glayout/flow/blocks/composite/opamp/opamp.py
Line 26 in e7f4611
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay so we need only the pcell for that? I am a bit confused. can you explain further.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The common source amp uses subdevices such as nmos. Each of those devices have their own netlists. You can directly connect those netlists using python code to make the netlist for the CS amp. You don't need to write any spice, just instantiate the subdevices in glayout and connect them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is another, probably better example.