"""Resistor components for IHP PDK."""
import gdsfactory as gf
from gdsfactory import Component
from gdsfactory.typings import LayerSpec
def add_rect(
component,
size: tuple[float, float],
layer: LayerSpec,
origin: tuple[float, float],
centered: bool = False,
):
"""Create rectangle, add ref to component and move to origin, return ref."""
rect = gf.components.rectangle(size=size, layer=layer, centered=centered)
ref = component.add_ref(rect)
ref.move(origin)
return ref
[docs]
@gf.cell
def rsil(
dy: float = 0.5,
dx: float = 0.5,
resistance: float | None = None,
model: str = "rsil",
layer_poly: LayerSpec = "PolyResdrawing",
layer_heat: LayerSpec = "HeatResdrawing",
layer_gate: LayerSpec = "GatPolydrawing",
layer_contact: LayerSpec = "Contdrawing",
layer_metal1: LayerSpec = "Metal1drawing",
layer_metal1_pin: LayerSpec = "Metal1pin",
layer_res_mark: LayerSpec = "RESdrawing",
layer_block: LayerSpec = "EXTBlockdrawing",
) -> Component:
"""Create a vertical silicided polysilicon resistor (i.e. with dy as its length)
Args:
dy: length of the resistor in micrometers.
dx: width of the resistor in micrometers.
resistance: Target resistance in ohms (optional).
model: Device model name.
layer_poly: Polysilicon layer.
layer_heat: Thermal resistor marker.
layer_gate: Gate polysilicon layer.
layer_contact: Contact layer.
layer_metal1: Metal1 layer.
layer_metal1_pin: Metal1 pin layer.
layer_res_mark: Resistor marker layer.
layer_block: Blocking layer.
Returns:
Component with silicided poly resistor layout.
"""
c = Component()
# Constants
RSIL_MIN_DY = 0.4
RSIL_MIN_DX = 0.4
GRID = 0.005
SHEET_RESISTANCE = 7.0
GAT_DY = 0.35
# Geometry
METAL_PAD_DY = 0.26
GAT_METAL_MARGIN = 0.02
METAL_CONTACT_MARGIN = 0.05
BLOCK_MARGIN = 0.18
# Validate / snap to grid
dy = max(dy, RSIL_MIN_DY)
dx = max(dx, RSIL_MIN_DX)
dy = round(dy / GRID) * GRID
dx = round(dx / GRID) * GRID
# Resistance calculation
if resistance is None:
n_squares = dy / dx
resistance = n_squares * SHEET_RESISTANCE
else:
n_squares = dy / dx
# Compute geometry
# Resistor body bottom-left at (0,0)
body_origin = (0.0, 0.0)
# Pad sizes
metal_pad_dx = dx - 2 * GAT_METAL_MARGIN
metal_pad_dy = METAL_PAD_DY
# Pad coordinates
metal_pad_left_x = GAT_METAL_MARGIN
metal_pad_upper_y = dy + GAT_DY - metal_pad_dy - GAT_METAL_MARGIN
metal_pad_lower_y = -GAT_DY + GAT_METAL_MARGIN
# Contacts inside pads
contact_dx = metal_pad_dx - 2 * METAL_CONTACT_MARGIN
contact_dy = metal_pad_dy - 2 * METAL_CONTACT_MARGIN
contact_x = metal_pad_left_x + METAL_CONTACT_MARGIN
contact_upper_y = metal_pad_upper_y + METAL_CONTACT_MARGIN
contact_lower_y = metal_pad_lower_y + METAL_CONTACT_MARGIN
# blocking rectangle size & origin
block_dx = dx + 2 * BLOCK_MARGIN
block_dy = dy + 2 * (GAT_DY + BLOCK_MARGIN)
block_origin = ((dx - block_dx) / 2.0, (dy - block_dy) / 2.0)
# Draw resistor body (polysilicon + heat + res marker)
for ly in (layer_poly, layer_heat, layer_res_mark):
add_rect(c, size=(dx, dy), layer=ly, origin=body_origin)
# Gate extensions (top and bottom)
gate_size = (dx, GAT_DY)
add_rect(c, size=gate_size, layer=layer_gate, origin=(0.0, dy))
add_rect(c, size=gate_size, layer=layer_gate, origin=(0.0, -GAT_DY))
# Metal pads (pin then metal1)
for ly in (layer_metal1_pin, layer_metal1):
add_rect(
c,
size=(metal_pad_dx, metal_pad_dy),
layer=ly,
origin=(metal_pad_left_x, metal_pad_upper_y),
)
add_rect(
c,
size=(metal_pad_dx, metal_pad_dy),
layer=ly,
origin=(metal_pad_left_x, metal_pad_lower_y),
)
# Contacts (inside metal pads)
add_rect(
c,
size=(contact_dx, contact_dy),
layer=layer_contact,
origin=(contact_x, contact_upper_y),
)
add_rect(
c,
size=(contact_dx, contact_dy),
layer=layer_contact,
origin=(contact_x, contact_lower_y),
)
# Blocking layer
add_rect(c, size=(block_dx, block_dy), layer=layer_block, origin=block_origin)
# Ports (derive from pad geometry)
pad_center_x = metal_pad_left_x + metal_pad_dx / 2.0
pad_upper_center_y = metal_pad_upper_y + metal_pad_dy / 2.0
pad_lower_center_y = metal_pad_lower_y + metal_pad_dy / 2.0
c.add_port(
name="P1",
center=(pad_center_x, pad_upper_center_y),
width=metal_pad_dx,
orientation=90,
layer=layer_metal1,
port_type="electrical",
)
c.add_port(
name="P2",
center=(pad_center_x, pad_lower_center_y),
width=metal_pad_dx,
orientation=270,
layer=layer_metal1,
port_type="electrical",
)
# Metadata
c.info.update(
{
"model": model,
"dy": dy,
"dx": dx,
"resistance": resistance,
"sheet_resistance": SHEET_RESISTANCE,
"n_squares": n_squares,
}
)
return c
[docs]
@gf.cell
def rppd(
dy: float = 0.5,
dx: float = 0.5,
resistance: float | None = None,
model: str = "rsil",
layer_poly: LayerSpec = "PolyResdrawing",
layer_heat: LayerSpec = "HeatResdrawing",
layer_gate: LayerSpec = "GatPolydrawing",
layer_contact: LayerSpec = "Contdrawing",
layer_metal1: LayerSpec = "Metal1drawing",
layer_metal1_pin: LayerSpec = "Metal1pin",
layer_pSD: LayerSpec = "pSDdrawing",
layer_block: LayerSpec = "EXTBlockdrawing",
layer_sal_block: LayerSpec = "SalBlockdrawing",
) -> Component:
"""Create a vertical P+ polysilicon resistor (i.e. with dy as its length).
Args:
dy: length of the resistor in micrometers.
dx: width of the resistor in micrometers.
resistance: Target resistance in ohms (optional).
model: Device model name.
layer_poly: Polysilicon layer.
layer_heat: Thermal resistor marker.
layer_gate: Gate polysilicon layer.
layer_contact: Contact layer.
layer_metal1: Metal1 layer.
layer_metal1_pin: Metal1 pin layer.
layer_pSD: PSD layer.
layer_block: Blocking layer.
layer_sal_block: Salicide block layer.
Returns:
Component with P+ resistor layout.
"""
c = Component()
# Constants
RPPD_MIN_DY = 0.4
RPPD_MIN_DX = 0.5
GRID = 0.005
SHEET_RESISTANCE = 300.0
GAT_DY = 0.43
# Geometry
METAL_PAD_DY = 0.30
METAL_CONTACT_MARGIN_DX = 0.05
METAL_CONTACT_MARGIN_DY = 0.07
GAT_METAL_MARGIN_DX = 0.02
GAT_METAL_MARGIN_DY = 0.00
BLOCK_MARGIN = 0.18
BLOCK2_MARGIN = 0.02
# Validate
dy = max(dy, RPPD_MIN_DY)
dx = max(dx, RPPD_MIN_DX)
dy = round(dy / GRID) * GRID
dx = round(dx / GRID) * GRID
# Resistance calculation
if resistance is None:
n_squares = dy / dx
resistance = n_squares * SHEET_RESISTANCE
else:
n_squares = dy / dx
# Geometry
body_origin = (0.0, 0.0)
# Metal pad sizes
metal_pad_dx = dx - 2 * GAT_METAL_MARGIN_DX
metal_pad_dy = METAL_PAD_DY
# Metal pad coordinates
metal_pad_left_x = GAT_METAL_MARGIN_DX
metal_pad_upper_y = dy + GAT_DY - metal_pad_dy - GAT_METAL_MARGIN_DY
metal_pad_lower_y = -GAT_DY + GAT_METAL_MARGIN_DY
# Contact sizes
contact_dx = metal_pad_dx - 2 * METAL_CONTACT_MARGIN_DX
contact_dy = metal_pad_dy - 2 * METAL_CONTACT_MARGIN_DY
contact_left_x = metal_pad_left_x + METAL_CONTACT_MARGIN_DX
contact_upper_y = metal_pad_upper_y + METAL_CONTACT_MARGIN_DY
contact_lower_y = metal_pad_lower_y + METAL_CONTACT_MARGIN_DY
# Blocking layers
block_dx = dx + 2 * BLOCK_MARGIN
block_dy = dy + 2 * (GAT_DY + BLOCK_MARGIN)
block_origin = ((dx - block_dx) / 2.0, (dy - block_dy) / 2.0)
block2_dx = block_dx + 2 * BLOCK2_MARGIN
block2_dy = dy
block2_origin = ((dx - block2_dx) / 2.0, (dy - block2_dy) / 2.0)
# Draw resistor body
for ly in (layer_poly, layer_heat):
add_rect(c, size=(dx, dy), layer=ly, origin=body_origin)
# Gate poly extensions
gate_size = (dx, GAT_DY)
add_rect(c, size=gate_size, layer=layer_gate, origin=(0.0, dy))
add_rect(c, size=gate_size, layer=layer_gate, origin=(0.0, -GAT_DY))
# Contacts
add_rect(
c,
size=(contact_dx, contact_dy),
layer=layer_contact,
origin=(contact_left_x, contact_upper_y),
)
add_rect(
c,
size=(contact_dx, contact_dy),
layer=layer_contact,
origin=(contact_left_x, contact_lower_y),
)
# Metal pads (pin + metal1)
for ly in (layer_metal1_pin, layer_metal1):
add_rect(
c,
size=(metal_pad_dx, metal_pad_dy),
layer=ly,
origin=(metal_pad_left_x, metal_pad_upper_y),
)
add_rect(
c,
size=(metal_pad_dx, metal_pad_dy),
layer=ly,
origin=(metal_pad_left_x, metal_pad_lower_y),
)
# Blocking layers
for ly in (layer_block, layer_pSD):
add_rect(c, size=(block_dx, block_dy), layer=ly, origin=block_origin)
for ly in (layer_block, layer_sal_block):
add_rect(c, size=(block2_dx, block2_dy), layer=ly, origin=block2_origin)
# Ports
metal_pad_center_x = metal_pad_left_x + metal_pad_dx / 2.0
metal_pad_upper_center_y = metal_pad_upper_y + metal_pad_dy / 2.0
metal_pad_lower_center_y = metal_pad_lower_y + metal_pad_dy / 2.0
c.add_port(
name="P1",
center=(metal_pad_center_x, metal_pad_upper_center_y),
width=metal_pad_dx,
orientation=90,
layer=layer_metal1,
port_type="electrical",
)
c.add_port(
name="P2",
center=(metal_pad_center_x, metal_pad_lower_center_y),
width=metal_pad_dx,
orientation=270,
layer=layer_metal1,
port_type="electrical",
)
# Metadata
c.info.update(
{
"model": model,
"dy": dy,
"dx": dx,
"resistance": resistance,
"sheet_resistance": SHEET_RESISTANCE,
"n_squares": n_squares,
}
)
return c
[docs]
@gf.cell
def rhigh(
dy: float = 0.96,
dx: float = 0.5,
resistance: float | None = None,
model: str = "rsil",
layer_poly: LayerSpec = "PolyResdrawing",
layer_heat: LayerSpec = "HeatResdrawing",
layer_gate: LayerSpec = "GatPolydrawing",
layer_contact: LayerSpec = "Contdrawing",
layer_metal1: LayerSpec = "Metal1drawing",
layer_metal1_pin: LayerSpec = "Metal1pin",
layer_pSD: LayerSpec = "pSDdrawing",
layer_nSD: LayerSpec = "nSDdrawing",
layer_block: LayerSpec = "EXTBlockdrawing",
layer_sal_block: LayerSpec = "SalBlockdrawing",
) -> Component:
"""Create a vertical high-resistance polysilicon resistor (i.e. with dy as its length).
Args:
dy: length of the resistor in micrometers.
dx: width of the resistor in micrometers.
resistance: Target resistance in ohms (optional).
model: Device model name.
layer_poly: Polysilicon layer.
layer_heat: Thermal resistor marker.
layer_gate: Gate polysilicon layer.
layer_contact: Contact layer.
layer_metal1: Metal1 layer.
layer_metal1_pin: Metal1 pin layer.
layer_pSD: PSD layer.
layer_nSD: NSD layer
layer_block: Blocking layer.
layer_sal_block: Salicide block layer.
Returns:
Component with high-resistance poly resistor layout.
"""
c = Component()
# Constants
RHIGH_MIN_DY = 0.4
RHIGH_MIN_DX = 0.5
GRID = 0.005
SHEET_RESISTANCE = 300.0
GAT_DY = 0.43
# Fundamental geometry constants
METAL_PAD_DY = 0.26
METAL_CONTACT_MARGIN = 0.05
GAT_METAL_MARGIN = 0.02
BLOCK1_MARGIN = 0.18
BLOCK2_MARGIN = 0.02
# Validate
dy = max(dy, RHIGH_MIN_DY)
dx = max(dx, RHIGH_MIN_DX)
dy = round(dy / GRID) * GRID
dx = round(dx / GRID) * GRID
# Resistance calculation
if resistance is None:
n_squares = dy / dx
resistance = n_squares * SHEET_RESISTANCE
else:
n_squares = dy / dx
# Compute geometry
body_origin = (0.0, 0.0)
# Metal pad sizes
metal_pad_dx = dx - 2 * GAT_METAL_MARGIN
metal_pad_dy = METAL_PAD_DY
# Metal pad positions
metal_pad_left_x = GAT_METAL_MARGIN
metal_pad_upper_y = dy + GAT_DY - metal_pad_dy - GAT_METAL_MARGIN
metal_pad_lower_y = -GAT_DY + GAT_METAL_MARGIN
# Contacts inside metal pads
contact_dx = metal_pad_dx - 2 * METAL_CONTACT_MARGIN
contact_dy = metal_pad_dy - 2 * METAL_CONTACT_MARGIN
contact_left_x = metal_pad_left_x + METAL_CONTACT_MARGIN
contact_upper_y = metal_pad_upper_y + METAL_CONTACT_MARGIN
contact_lower_y = metal_pad_lower_y + METAL_CONTACT_MARGIN
# Blocking layer geometry
block1_dx = dx + 2 * BLOCK1_MARGIN
block1_dy = dy + 2 * (GAT_DY + BLOCK1_MARGIN)
block1_origin = ((dx - block1_dx) / 2, (dy - block1_dy) / 2)
block2_dx = block1_dx + 2 * BLOCK2_MARGIN
block2_dy = dy
block2_origin = ((dx - block2_dx) / 2, (dy - block2_dy) / 2)
# Draw resistor body (poly + heat)
for ly in (layer_poly, layer_heat):
add_rect(c, size=(dx, dy), layer=ly, origin=body_origin)
# Gate extensions
gate_size = (dx, GAT_DY)
add_rect(c, gate_size, layer_gate, origin=(0.0, dy))
add_rect(c, gate_size, layer_gate, origin=(0.0, -GAT_DY))
# Contacts
add_rect(
c,
(contact_dx, contact_dy),
layer_contact,
origin=(contact_left_x, contact_upper_y),
)
add_rect(
c,
(contact_dx, contact_dy),
layer_contact,
origin=(contact_left_x, contact_lower_y),
)
# Metal pads
for ly in (layer_metal1_pin, layer_metal1):
add_rect(
c,
(metal_pad_dx, metal_pad_dy),
ly,
origin=(metal_pad_left_x, metal_pad_upper_y),
)
add_rect(
c,
(metal_pad_dx, metal_pad_dy),
ly,
origin=(metal_pad_left_x, metal_pad_lower_y),
)
# Blocking 1
for ly in (layer_block, layer_pSD, layer_nSD):
add_rect(c, (block1_dx, block1_dy), ly, origin=block1_origin)
# Blocking 2
for ly in (layer_block, layer_sal_block):
add_rect(c, (block2_dx, block2_dy), ly, origin=block2_origin)
# Ports
metal_pad_center_x = metal_pad_left_x + metal_pad_dx / 2.0
metal_pad_upper_center_y = metal_pad_upper_y + metal_pad_dy / 2.0
metal_pad_lower_center_y = metal_pad_lower_y + metal_pad_dy / 2.0
c.add_port(
name="P1",
center=(metal_pad_center_x, metal_pad_upper_center_y),
width=metal_pad_dx,
orientation=90,
layer=layer_metal1,
port_type="electrical",
)
c.add_port(
name="P2",
center=(metal_pad_center_x, metal_pad_lower_center_y),
width=metal_pad_dx,
orientation=270,
layer=layer_metal1,
port_type="electrical",
)
# Metadata
c.info.update(
{
"model": model,
"dy": dy,
"dx": dx,
"resistance": resistance,
"sheet_resistance": SHEET_RESISTANCE,
"n_squares": n_squares,
}
)
return c
if __name__ == "__main__":
from gdsfactory.difftest import xor
from ihp import PDK
from ihp.cells import fixed
PDK.activate()
# Test the components
c0 = fixed.rsil() # original
c1 = rsil() # New
c = xor(c0, c1)
c.show()
# c0 = fixed.rppd() # original
# c1 = rppd() # New
# c = xor(c0, c1)
# c.show()
# c0 = fixed.rhigh() # original
# c1 = rhigh() # New
# c = xor(c0, c1)
# c.show()