Source code for ihp.cells.resistors

"""Resistor components for IHP PDK."""

import gdsfactory as gf
from gdsfactory import Component

# Define layers for resistors
LAYERS = {
    "Rsil": (6, 10),
    "Rppd": (31, 10),
    "Rhigh": (85, 0),
    "PolyRes": (86, 0),
    "Activ": (1, 0),
    "GatPoly": (5, 0),
    "pSD": (14, 0),
    "nSD": (16, 0),
    "NWell": (31, 0),
    "SiProtection": (2, 6),
    "Cont": (6, 0),
    "Metal1": (8, 0),
    "Metal2": (10, 0),
    "Via1": (19, 0),
    "ResistorMark": (110, 5),
    "TEXT": (63, 63),
}


[docs] @gf.cell def rsil( width: float = 0.8, length: float = 10.0, resistance: float | None = None, model: str = "rsil", ) -> Component: """Create a silicided polysilicon resistor. Args: width: Width of the resistor in micrometers. length: Length of the resistor in micrometers. resistance: Target resistance in ohms (optional). model: Device model name. Returns: Component with silicided poly resistor layout. """ c = Component() # Design rules rsil_min_width = 0.4 rsil_min_length = 0.8 sheet_resistance = 7.0 # ohms/square (example) cont_size = 0.16 cont_enc = 0.07 metal_enc = 0.06 end_extension = 0.4 # Validate dimensions width = max(width, rsil_min_width) length = max(length, rsil_min_length) # Grid snap grid = 0.005 width = round(width / grid) * grid length = round(length / grid) * grid # Calculate resistance if not provided if resistance is None: n_squares = length / width resistance = n_squares * sheet_resistance # Create resistor body (polysilicon) res_body = gf.components.rectangle( size=(length, width), layer=LAYERS["GatPoly"], centered=True, ) c.add_ref(res_body) # Silicide blocking layer sil_block = gf.components.rectangle( size=(length + 0.2, width + 0.2), layer=LAYERS["Rsil"], centered=True, ) c.add_ref(sil_block) # End contact regions (polysilicon extensions) # Left contact region left_contact = gf.components.rectangle( size=(end_extension, width), layer=LAYERS["GatPoly"], ) left_ref = c.add_ref(left_contact) left_ref.move((-(length / 2 + end_extension), -width / 2)) # Right contact region right_contact = gf.components.rectangle( size=(end_extension, width), layer=LAYERS["GatPoly"], ) right_ref = c.add_ref(right_contact) right_ref.move((length / 2, -width / 2)) # Contacts at ends n_cont_y = int((width - cont_size) / (cont_size + 0.18)) + 1 for i in range(n_cont_y): y_pos = -width / 2 + cont_enc + i * (cont_size + 0.18) # Left contact cont_left = gf.components.rectangle( size=(cont_size, cont_size), layer=LAYERS["Cont"], ) cont_left_ref = c.add_ref(cont_left) cont_left_ref.move((-(length / 2 + end_extension / 2) - cont_size / 2, y_pos)) # Right contact cont_right = gf.components.rectangle( size=(cont_size, cont_size), layer=LAYERS["Cont"], ) cont_right_ref = c.add_ref(cont_right) cont_right_ref.move(((length / 2 + end_extension / 2) - cont_size / 2, y_pos)) # Metal1 connections # Left metal m1_left = gf.components.rectangle( size=(end_extension + 2 * metal_enc, width + 2 * metal_enc), layer=LAYERS["Metal1"], ) m1_left_ref = c.add_ref(m1_left) m1_left_ref.move( (-(length / 2 + end_extension + metal_enc), -width / 2 - metal_enc) ) # Right metal m1_right = gf.components.rectangle( size=(end_extension + 2 * metal_enc, width + 2 * metal_enc), layer=LAYERS["Metal1"], ) m1_right_ref = c.add_ref(m1_right) m1_right_ref.move((length / 2 - metal_enc, -width / 2 - metal_enc)) # Resistor marker res_mark = gf.components.rectangle( size=(length + 2 * end_extension + 0.5, width + 0.5), layer=LAYERS["ResistorMark"], centered=True, ) c.add_ref(res_mark) # Add ports c.add_port( name="P1", center=(-(length / 2 + end_extension), 0), width=width, orientation=180, layer=LAYERS["Metal1"], port_type="electrical", ) c.add_port( name="P2", center=(length / 2 + end_extension, 0), width=width, orientation=0, layer=LAYERS["Metal1"], port_type="electrical", ) # Add metadata c.info["model"] = model c.info["width"] = width c.info["length"] = length c.info["resistance"] = resistance c.info["sheet_resistance"] = sheet_resistance c.info["n_squares"] = length / width return c
[docs] @gf.cell def rppd( width: float = 0.8, length: float = 10.0, resistance: float | None = None, model: str = "rppd", ) -> Component: """Create a P+ polysilicon resistor. Args: width: Width of the resistor in micrometers. length: Length of the resistor in micrometers. resistance: Target resistance in ohms (optional). model: Device model name. Returns: Component with P+ poly resistor layout. """ c = Component() # Design rules rppd_min_width = 0.4 rppd_min_length = 0.8 sheet_resistance = 300.0 # ohms/square (high resistance) cont_size = 0.16 cont_enc = 0.07 metal_enc = 0.06 end_extension = 0.4 # Validate dimensions width = max(width, rppd_min_width) length = max(length, rppd_min_length) # Grid snap grid = 0.005 width = round(width / grid) * grid length = round(length / grid) * grid # Calculate resistance if not provided if resistance is None: n_squares = length / width resistance = n_squares * sheet_resistance # Create resistor body (polysilicon) res_body = gf.components.rectangle( size=(length, width), layer=LAYERS["GatPoly"], centered=True, ) c.add_ref(res_body) # P+ doping layer p_doping = gf.components.rectangle( size=(length + 2 * end_extension, width + 0.2), layer=LAYERS["pSD"], centered=True, ) c.add_ref(p_doping) # RPPD marker layer rppd_mark = gf.components.rectangle( size=(length, width), layer=LAYERS["Rppd"], centered=True, ) c.add_ref(rppd_mark) # End contact regions # Left contact region left_contact = gf.components.rectangle( size=(end_extension, width), layer=LAYERS["GatPoly"], ) left_ref = c.add_ref(left_contact) left_ref.move((-(length / 2 + end_extension), -width / 2)) # Right contact region right_contact = gf.components.rectangle( size=(end_extension, width), layer=LAYERS["GatPoly"], ) right_ref = c.add_ref(right_contact) right_ref.move((length / 2, -width / 2)) # Contacts at ends n_cont_y = int((width - cont_size) / (cont_size + 0.18)) + 1 for i in range(n_cont_y): y_pos = -width / 2 + cont_enc + i * (cont_size + 0.18) # Left contact cont_left = gf.components.rectangle( size=(cont_size, cont_size), layer=LAYERS["Cont"], ) cont_left_ref = c.add_ref(cont_left) cont_left_ref.move((-(length / 2 + end_extension / 2) - cont_size / 2, y_pos)) # Right contact cont_right = gf.components.rectangle( size=(cont_size, cont_size), layer=LAYERS["Cont"], ) cont_right_ref = c.add_ref(cont_right) cont_right_ref.move(((length / 2 + end_extension / 2) - cont_size / 2, y_pos)) # Metal1 connections # Left metal m1_left = gf.components.rectangle( size=(end_extension + 2 * metal_enc, width + 2 * metal_enc), layer=LAYERS["Metal1"], ) m1_left_ref = c.add_ref(m1_left) m1_left_ref.move( (-(length / 2 + end_extension + metal_enc), -width / 2 - metal_enc) ) # Right metal m1_right = gf.components.rectangle( size=(end_extension + 2 * metal_enc, width + 2 * metal_enc), layer=LAYERS["Metal1"], ) m1_right_ref = c.add_ref(m1_right) m1_right_ref.move((length / 2 - metal_enc, -width / 2 - metal_enc)) # Resistor marker res_mark = gf.components.rectangle( size=(length + 2 * end_extension + 0.5, width + 0.5), layer=LAYERS["ResistorMark"], centered=True, ) c.add_ref(res_mark) # Add ports c.add_port( name="P1", center=(-(length / 2 + end_extension), 0), width=width, orientation=180, layer=LAYERS["Metal1"], port_type="electrical", ) c.add_port( name="P2", center=(length / 2 + end_extension, 0), width=width, orientation=0, layer=LAYERS["Metal1"], port_type="electrical", ) # Add metadata c.info["model"] = model c.info["width"] = width c.info["length"] = length c.info["resistance"] = resistance c.info["sheet_resistance"] = sheet_resistance c.info["n_squares"] = length / width return c
[docs] @gf.cell def rhigh( width: float = 1.4, length: float = 20.0, resistance: float | None = None, model: str = "rhigh", ) -> Component: """Create a high-resistance polysilicon resistor. Args: width: Width of the resistor in micrometers. length: Length of the resistor in micrometers. resistance: Target resistance in ohms (optional). model: Device model name. Returns: Component with high-resistance poly resistor layout. """ c = Component() # Design rules rhigh_min_width = 1.4 rhigh_min_length = 5.0 sheet_resistance = 1350.0 # ohms/square (very high resistance) cont_size = 0.16 cont_enc = 0.07 metal_enc = 0.06 end_extension = 0.8 isolation_enc = 0.5 # Validate dimensions width = max(width, rhigh_min_width) length = max(length, rhigh_min_length) # Grid snap grid = 0.005 width = round(width / grid) * grid length = round(length / grid) * grid # Calculate resistance if not provided if resistance is None: n_squares = length / width resistance = n_squares * sheet_resistance # N-Well for isolation nwell = gf.components.rectangle( size=( length + 2 * end_extension + 2 * isolation_enc, width + 2 * isolation_enc, ), layer=LAYERS["NWell"], centered=True, ) c.add_ref(nwell) # Create resistor body (polysilicon) res_body = gf.components.rectangle( size=(length, width), layer=LAYERS["GatPoly"], centered=True, ) c.add_ref(res_body) # High resistance marker rhigh_mark = gf.components.rectangle( size=(length + 0.2, width + 0.2), layer=LAYERS["Rhigh"], centered=True, ) c.add_ref(rhigh_mark) # End contact regions # Left contact region left_contact = gf.components.rectangle( size=(end_extension, width), layer=LAYERS["GatPoly"], ) left_ref = c.add_ref(left_contact) left_ref.move((-(length / 2 + end_extension), -width / 2)) # Right contact region right_contact = gf.components.rectangle( size=(end_extension, width), layer=LAYERS["GatPoly"], ) right_ref = c.add_ref(right_contact) right_ref.move((length / 2, -width / 2)) # Contacts at ends (larger contacts for high resistance) n_cont_x = 2 # Multiple contacts in X for better connection n_cont_y = int((width - cont_size) / (cont_size + 0.18)) + 1 for i in range(n_cont_x): for j in range(n_cont_y): x_offset = i * (cont_size + 0.18) y_pos = -width / 2 + cont_enc + j * (cont_size + 0.18) # Left contacts cont_left = gf.components.rectangle( size=(cont_size, cont_size), layer=LAYERS["Cont"], ) cont_left_ref = c.add_ref(cont_left) cont_left_ref.move( (-(length / 2 + end_extension - cont_enc - x_offset), y_pos) ) # Right contacts cont_right = gf.components.rectangle( size=(cont_size, cont_size), layer=LAYERS["Cont"], ) cont_right_ref = c.add_ref(cont_right) cont_right_ref.move( (length / 2 + end_extension - cont_enc - cont_size - x_offset, y_pos) ) # Metal1 connections (wider for lower contact resistance) # Left metal m1_left = gf.components.rectangle( size=(end_extension + 2 * metal_enc, width + 2 * metal_enc), layer=LAYERS["Metal1"], ) m1_left_ref = c.add_ref(m1_left) m1_left_ref.move( (-(length / 2 + end_extension + metal_enc), -width / 2 - metal_enc) ) # Right metal m1_right = gf.components.rectangle( size=(end_extension + 2 * metal_enc, width + 2 * metal_enc), layer=LAYERS["Metal1"], ) m1_right_ref = c.add_ref(m1_right) m1_right_ref.move((length / 2 - metal_enc, -width / 2 - metal_enc)) # Resistor marker res_mark = gf.components.rectangle( size=(length + 2 * end_extension + 1.0, width + 1.0), layer=LAYERS["ResistorMark"], centered=True, ) c.add_ref(res_mark) # Add ports c.add_port( name="P1", center=(-(length / 2 + end_extension), 0), width=width, orientation=180, layer=LAYERS["Metal1"], port_type="electrical", ) c.add_port( name="P2", center=(length / 2 + end_extension, 0), width=width, orientation=0, layer=LAYERS["Metal1"], port_type="electrical", ) # Add metadata c.info["model"] = model c.info["width"] = width c.info["length"] = length c.info["resistance"] = resistance c.info["sheet_resistance"] = sheet_resistance c.info["n_squares"] = length / width return c
if __name__ == "__main__": # Test the components c1 = rsil(width=1.0, length=10.0) c1.show() c2 = rppd(width=0.8, length=20.0) c2.show() c3 = rhigh(width=1.4, length=50.0) c3.show()