diff --git a/ihp/cells/antennas.py b/ihp/cells/antennas.py index b08ee83..a5febd3 100644 --- a/ihp/cells/antennas.py +++ b/ihp/cells/antennas.py @@ -120,7 +120,23 @@ def DrawContArray( return x_min, y_min, x_max, y_max -@gf.cell +@gf.cell( + tags=["IHP", "diode", "antenna"], + symbol="diode", + ports={"left": ["1"], "right": ["2"]}, + models=[{ + "language": "spice", + "name": "dantenna", + "spice_type": "SUBCKT", + "library": "cornerDIO.lib", + "sections": ["dio_tt", "dio_ss", "dio_ff"], + "port_order": ["1", "2"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + }, + }], +) def dantenna( width: float = 0.78, length: float = 0.78, @@ -225,20 +241,26 @@ def dantenna( ) ).move((-diods_over, -diods_over)) - # VLSIR Simulation Metadata - c.info["vlsir"] = { - "model": "dantenna", - "spice_type": "SUBCKT", - "spice_lib": "diodes.lib", - "port_order": ["1", "2"], - "port_map": {}, # No physical ports defined on component - "params": {"w": width * 1e-6, "l": length * 1e-6}, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "diode", "antenna"], + symbol="diode", + ports={"left": ["1"], "right": ["2"]}, + models=[{ + "language": "spice", + "name": "dpantenna", + "spice_type": "SUBCKT", + "library": "cornerDIO.lib", + "sections": ["dio_tt", "dio_ss", "dio_ff"], + "port_order": ["1", "2"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + }, + }], +) def dpantenna( width: float = 0.78, length: float = 0.78, @@ -348,16 +370,6 @@ def dpantenna( ) ).move((-NW_c, -NW_c)) - # VLSIR Simulation Metadata - c.info["vlsir"] = { - "model": "dpantenna", - "spice_type": "SUBCKT", - "spice_lib": "diodes.lib", - "port_order": ["1", "2"], - "port_map": {}, # No physical ports defined on component - "params": {"w": width * 1e-6, "l": length * 1e-6}, - } - return c diff --git a/ihp/cells/bjt_transistors.py b/ihp/cells/bjt_transistors.py index b77bbd6..806ed89 100644 --- a/ihp/cells/bjt_transistors.py +++ b/ihp/cells/bjt_transistors.py @@ -29,7 +29,25 @@ def _snap_width_to_grid(width_um: float) -> float: return round(w / grid) * grid -@gf.cell +@gf.cell( + tags=["IHP", "bjt", "npn"], + symbol="npn", + ports={"top": ["C"], "left": ["B"], "bottom": ["E"], "right": ["S"]}, + models=[{ + "language": "spice", + "name": "npn13G2", + "spice_type": "SUBCKT", + "library": "cornerHBT.lib", + "sections": ["hbt_typ", "hbt_bcs", "hbt_wcs"], + "port_order": ["C", "B", "E", "S"], + "params": { + "Nx": "Nx", + "Ny": "Ny", + "we": "emitter_width * 1e-6", + "le": "emitter_length * 1e-6", + }, + }], +) def npn13G2( baspolyx: float = 0.3, bipwinx: float = 0.07, @@ -720,27 +738,28 @@ def npn13G2( port_type="electrical", ) - # VLSIR Simulation Metadata - c.info["vlsir"] = { - "model": "npn13G2", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_hbt_mod.lib", - "port_order": ["c", "b", "e", "bn"], - "port_map": {"C": "c", "B": "b", "E": "e"}, - "params": { - "Nx": Nx, - "Ny": Ny, - "we": emitter_width * 1e-6, - "le": emitter_length * 1e-6, - }, - } - # TODO: Extend to handle empoly, bipwin, cmet return c -@gf.cell +@gf.cell( + tags=["IHP", "bjt", "npn"], + symbol="npn", + ports={"top": ["C"], "left": ["B"], "bottom": ["E"], "right": ["S"]}, + models=[{ + "language": "spice", + "name": "npn13G2l", + "spice_type": "SUBCKT", + "library": "cornerHBT.lib", + "sections": ["hbt_typ", "hbt_bcs", "hbt_wcs"], + "port_order": ["C", "B", "E", "S"], + "params": { + "we": "emitter_width * 1e-6", + "le": "emitter_length * 1e-6", + }, + }], +) def npn13G2L( emitter_length: float = 1, emitter_width: float = 0.07, @@ -1295,23 +1314,26 @@ def npn13G2L( ), ) - # VLSIR Simulation Metadata - c.info["vlsir"] = { - "model": "npn13G2l", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_hbt_mod.lib", - "port_order": ["c", "b", "e", "bn"], - "port_map": {"C": "c", "B": "b", "E": "e"}, - "params": { - "we": emitter_width * 1e-6, - "le": emitter_length * 1e-6, - }, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "bjt", "npn"], + symbol="npn", + ports={"top": ["C"], "left": ["B"], "bottom": ["E"], "right": ["S"]}, + models=[{ + "language": "spice", + "name": "npn13G2v", + "spice_type": "SUBCKT", + "library": "cornerHBT.lib", + "sections": ["hbt_typ", "hbt_bcs", "hbt_wcs"], + "port_order": ["C", "B", "E", "S"], + "params": { + "we": "emitter_width * 1e-6", + "le": "emitter_length * 1e-6", + }, + }], +) def npn13G2V( emitter_length: float = 1, emitter_width: float = 0.12, @@ -1887,19 +1909,6 @@ def npn13G2V( ), ) - # VLSIR Simulation Metadata - c.info["vlsir"] = { - "model": "npn13G2v", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_hbt_mod.lib", - "port_order": ["c", "b", "e", "bn"], - "port_map": {"C": "c", "B": "b", "E": "e"}, - "params": { - "we": emitter_width * 1e-6, - "le": emitter_length * 1e-6, - }, - } - return c @@ -1992,7 +2001,19 @@ def contactArray( x = x + ws + dsx -@gf.cell +@gf.cell( + tags=["IHP", "bjt", "pnp"], + symbol="pnp", + ports={"top": ["C"], "left": ["B"], "bottom": ["E"]}, + models=[{ + "language": "spice", + "name": "pnpMPA", + "spice_type": "SUBCKT", + "library": "cornerHBT.lib", + "sections": ["hbt_typ", "hbt_bcs", "hbt_wcs"], + "port_order": ["C", "B", "E"], + }], +) def pnpMPA(length: float = 2, width: float = 0.7) -> gf.Component: """Returns the IHP pnpMPA BJT transistor as a gdsfactory Component. @@ -2446,14 +2467,6 @@ def pnpMPA(length: float = 2, width: float = 0.7) -> gf.Component: port_type="electrical", ) - c.info["vlsir"] = { - "model": "pnpMPA", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_hbt_mod.lib", - "port_order": ["c", "b", "e"], - "port_map": {"MINUS": "c", "TIE": "b", "PLUS": "e"}, - } - return c diff --git a/ihp/cells/bondpads.py b/ihp/cells/bondpads.py index 4fc33fa..071719f 100644 --- a/ihp/cells/bondpads.py +++ b/ihp/cells/bondpads.py @@ -22,7 +22,18 @@ def regular_octagon_points(diameter: float): ] -@gf.cell +@gf.cell( + tags=["IHP", "bondpad"], + symbol="ckt", + ports={"left": ["PAD"]}, + models=[{ + "language": "spice", + "name": "bondpad", + "spice_type": "SUBCKT", + "library": "sg13g2_bondpad.lib", + "port_order": ["PAD"], + }], +) def bondpad( shape: Literal["octagon", "square", "circle"] = "octagon", diameter: float = 80.0, @@ -102,19 +113,6 @@ def bondpad( c.info["diameter"] = diameter c.info["top_metal"] = layer_top_metal - # VLSIR Simulation Metadata - c.info["vlsir"] = { - "model": "bondpad", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_bondpad.lib", - "port_order": ["PAD"], - "port_map": {"pad": "PAD"}, - "params": { - "size": diameter * 1e-6, - "shape": {"octagon": 0, "square": 1, "circle": 2}[shape], - "padtype": 0, # TODO - }, - } return c diff --git a/ihp/cells/capacitors.py b/ihp/cells/capacitors.py index d0a990e..09aec38 100644 --- a/ihp/cells/capacitors.py +++ b/ihp/cells/capacitors.py @@ -311,7 +311,23 @@ def cmom( return c -@gf.cell +@gf.cell( + tags=["IHP", "capacitor", "mim"], + symbol="capacitor", + ports={"left": ["PLUS"], "right": ["MINUS"]}, + models=[{ + "language": "spice", + "name": "cap_cmim", + "spice_type": "SUBCKT", + "library": "cornerCAP.lib", + "sections": ["cap_typ", "cap_bcs", "cap_wcs"], + "port_order": ["PLUS", "MINUS"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + }, + }], +) def cmim( width: float = 6.0, length: float = 6.0, @@ -329,7 +345,6 @@ def cmim( layer_topmetal1label: LayerSpec = "TopMetal1label", layer_metal5pin: LayerSpec = "Metal5pin", layer_topmetal1pin: LayerSpec = "TopMetal1pin", - model: str = "cmim", **kwargs, ) -> Component: """Create a MIM (Metal-Insulator-Metal) capacitor. @@ -354,8 +369,6 @@ def cmim( layer_metal5pin: Metal5 pin logic layer. layer_topmetal1pin: TopMetal1 pin logic layer. - model: Device model name. - Returns: Component with MIM capacitor layout. @@ -508,36 +521,43 @@ def cmim( layer=layer_text, ) - c.add_label(text=model, position=(c.x, c.y + width / 2), layer=layer_text) + c.add_label(text="cap_cmim", position=(c.x, c.y + width / 2), layer=layer_text) # fringe_factor = kwargs.get("fringe_factor", 0.355) # capacitance = width * length * mim_drc['mim_cap_density'] # capacitance *= (1+fringe_factor) - capacitance = CbCapCalc("C", 0, length, width, model) + capacitance = CbCapCalc("C", 0, length, width, "cap_cmim") c.add_label( text=f"C = {capacitance} fF", position=(c.x, c.y - width / 2), layer=layer_text ) - c.info["model"] = model + c.info["model"] = "cap_cmim" c.info["width"] = width c.info["length"] = length c.info["capacitance_fF"] = capacitance c.info["area_um2"] = width * length - # VLSIR simulation metadata - c.info["vlsir"] = { - "model": "cap_cmim", - "spice_type": "SUBCKT", - "spice_lib": "capacitors_mod.lib", - "port_order": ["PLUS", "MINUS"], - "params": {"w": width * 1e-6, "l": length * 1e-6}, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "capacitor", "mim", "rf"], + symbol="capacitor", + ports={"left": ["PLUS"], "right": ["MINUS"], "bottom": ["bn"]}, + models=[{ + "language": "spice", + "name": "cap_rfcmim", + "spice_type": "SUBCKT", + "library": "cornerCAP.lib", + "sections": ["cap_typ", "cap_bcs", "cap_wcs"], + "port_order": ["PLUS", "MINUS", "bn"], + "params": { + "l": "length * 1e-6", + "w": "width * 1e-6", + }, + }], +) def rfcmim( width: float = 7.0, length: float = 7.0, @@ -570,7 +590,6 @@ def rfcmim( layer_metal5label: LayerSpec = "Metal5label", layer_topmetal1label: LayerSpec = "TopMetal1label", layer_metal1label: LayerSpec = "Metal1label", - model: str = "rfcmim", ) -> Component: """Create a MIM (Metal-Insulator-Metal) capacitor isolated by a bulk charge-drift encapsulation P-Plus guard-ring. @@ -594,8 +613,6 @@ def rfcmim( layer_metal5pin: Metal5 pin logic layer. layer_topmetal1pin: TopMetal1 pin logic layer. - model: Device model name. - Returns: Component with MIM capacitor layout. @@ -630,9 +647,9 @@ def rfcmim( layer_topmetal1pin=layer_topmetal1pin, layer_metal5label=layer_metal5label, layer_topmetal1label=layer_topmetal1label, - model=model, ) c.info = cap.info + c.info["model"] = "cap_rfcmim" c.add_ref(cap) c.ports = cap.ports # add pwell block @@ -715,16 +732,6 @@ def rfcmim( c.add_label(text="TIE_LOW", position=(tie.x, tie.y), layer=layer_metal1label) c.add_label(text="TIE_LOW", position=(tie.x, tie.y), layer=layer_text) - # VLSIR simulation metadata - c.info["vlsir"] = { - "model": "cap_rfcmim", - "spice_type": "SUBCKT", - "spice_lib": "capacitors_mod.lib", - "port_order": ["PLUS", "MINUS", "bn"], - "port_map": {"PLUS": "PLUS", "MINUS": "MINUS"}, - "params": {"l": length * 1e-6, "w": width * 1e-6}, - } - return c diff --git a/ihp/cells/fet_transistors.py b/ihp/cells/fet_transistors.py index f620b54..4f273e6 100644 --- a/ihp/cells/fet_transistors.py +++ b/ihp/cells/fet_transistors.py @@ -505,13 +505,30 @@ def _mos_core( # --------------------------------------------------------------------------- # Public cell functions # --------------------------------------------------------------------------- -@gf.cell +@gf.cell( + tags=["IHP", "mos", "lv"], + symbol="nmos", + ports={"top": ["D"], "bottom": ["S"], "left": ["G"], "right": ["B"]}, + models=[{ + "language": "spice", + "name": "sg13_lv_nmos", + "spice_type": "SUBCKT", + "library": "cornerMOSlv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["D", "G", "S", "B"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + "ng": "nf", + "m": "m", + }, + }], +) def nmos( width: float = 0.15, length: float = 0.13, nf: int = 1, m: int = 1, - model: str = "sg13_lv_nmos", ) -> Component: """Create an NMOS transistor. @@ -520,7 +537,6 @@ def nmos( length: Gate length in micrometers. nf: Number of fingers. m: Multiplier (number of parallel devices). - model: Device model name. Returns: Component with NMOS transistor layout. @@ -541,31 +557,33 @@ def nmos( c = _mos_core(width, length, nf, is_pmos=False, is_hv=False) - # VLSIR simulation metadata - c.info["vlsir"] = { - "model": "sg13_lv_nmos", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_moslv_mod.lib", - "port_order": ["d", "g", "s", "b"], - "port_map": {"D": "d", "G": "g", "S": "s"}, - "params": { - "w": width * 1e-6, - "l": length * 1e-6, - "ng": nf, - "m": m, - }, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "mos", "lv"], + symbol="pmos", + ports={"top": ["D"], "bottom": ["S"], "left": ["G"], "right": ["B"]}, + models=[{ + "language": "spice", + "name": "sg13_lv_pmos", + "spice_type": "SUBCKT", + "library": "cornerMOSlv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["D", "G", "S", "B"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + "ng": "nf", + "m": "m", + }, + }], +) def pmos( width: float = 0.15, length: float = 0.13, nf: int = 1, m: int = 1, - model: str = "sg13_lv_pmos", ) -> Component: """Create a PMOS transistor. @@ -574,7 +592,6 @@ def pmos( length: Gate length in micrometers. nf: Number of fingers. m: Multiplier (number of parallel devices). - model: Device model name. Returns: Component with PMOS transistor layout. @@ -595,31 +612,33 @@ def pmos( c = _mos_core(width, length, nf, is_pmos=True, is_hv=False) - # VLSIR simulation metadata - c.info["vlsir"] = { - "model": "sg13_lv_pmos", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_moslv_mod.lib", - "port_order": ["d", "g", "s", "b"], - "port_map": {"D": "d", "G": "g", "S": "s"}, - "params": { - "w": width * 1e-6, - "l": length * 1e-6, - "ng": nf, - "m": m, - }, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "mos", "hv"], + symbol="nmos", + ports={"top": ["D"], "bottom": ["S"], "left": ["G"], "right": ["B"]}, + models=[{ + "language": "spice", + "name": "sg13_hv_nmos", + "spice_type": "SUBCKT", + "library": "cornerMOShv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["D", "G", "S", "B"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + "ng": "nf", + "m": "m", + }, + }], +) def nmos_hv( width: float = 0.60, length: float = 0.45, nf: int = 1, m: int = 1, - model: str = "sg13_hv_nmos", ) -> Component: """Create a high-voltage NMOS transistor. @@ -628,7 +647,6 @@ def nmos_hv( length: Gate length in micrometers. nf: Number of fingers. m: Multiplier (number of parallel devices). - model: Device model name. Returns: Component with HV NMOS transistor layout. @@ -649,31 +667,33 @@ def nmos_hv( c = _mos_core(width, length, nf, is_pmos=False, is_hv=True) - # VLSIR simulation metadata - c.info["vlsir"] = { - "model": "sg13_hv_nmos", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_moshv_mod.lib", - "port_order": ["d", "g", "s", "b"], - "port_map": {"D": "d", "G": "g", "S": "s"}, - "params": { - "w": width * 1e-6, - "l": length * 1e-6, - "ng": nf, - "m": m, - }, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "mos", "hv"], + symbol="pmos", + ports={"top": ["D"], "bottom": ["S"], "left": ["G"], "right": ["B"]}, + models=[{ + "language": "spice", + "name": "sg13_hv_pmos", + "spice_type": "SUBCKT", + "library": "cornerMOShv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["D", "G", "S", "B"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + "ng": "nf", + "m": "m", + }, + }], +) def pmos_hv( width: float = 0.30, length: float = 0.40, nf: int = 1, m: int = 1, - model: str = "sg13_hv_pmos", ) -> Component: """Create a high-voltage PMOS transistor. @@ -682,7 +702,6 @@ def pmos_hv( length: Gate length in micrometers. nf: Number of fingers. m: Multiplier (number of parallel devices). - model: Device model name. Returns: Component with HV PMOS transistor layout. @@ -703,21 +722,6 @@ def pmos_hv( c = _mos_core(width, length, nf, is_pmos=True, is_hv=True) - # VLSIR simulation metadata - c.info["vlsir"] = { - "model": "sg13_hv_pmos", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_moshv_mod.lib", - "port_order": ["d", "g", "s", "b"], - "port_map": {"D": "d", "G": "g", "S": "s"}, - "params": { - "w": width * 1e-6, - "l": length * 1e-6, - "ng": nf, - "m": m, - }, - } - return c diff --git a/ihp/cells/passives.py b/ihp/cells/passives.py index c1c99db..8d7effc 100644 --- a/ihp/cells/passives.py +++ b/ihp/cells/passives.py @@ -14,12 +14,28 @@ Point: TypeAlias = tuple[FloatLike, FloatLike] -@gf.cell +@gf.cell( + tags=["IHP", "varicap", "hv"], + symbol="ckt", + ports={"left": ["G1"], "right": ["W", "G2"], "bottom": ["bn"]}, + models=[{ + "language": "spice", + "name": "sg13_hv_svaricap", + "spice_type": "SUBCKT", + "library": "cornerMOShv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["G1", "W", "G2", "bn"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + "Nx": "nf", + }, + }], +) def svaricap( width: float = 1.0, length: float = 1.0, nf: int = 1, - model: str = "sg13_hv_svaricap", layer_nwell: LayerSpec = "NWelldrawing", layer_activ: LayerSpec = "Activdrawing", layer_gatpoly: LayerSpec = "GatPolydrawing", @@ -35,7 +51,6 @@ def svaricap( width: Width of the varicap in micrometers. length: Length of the varicap in micrometers. nf: Number of fingers. - model: Device model name. layer_nwell: N-well layer. layer_activ: Active region layer. layer_gatpoly: Gate polysilicon layer. @@ -175,25 +190,26 @@ def svaricap( port_type="electrical", ) - # Add VLSIR metadata - c.info["vlsir"] = { - "model": model, - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_svaricaphv_mod.lib", - "port_order": ["G1", "W", "G2", "bn"], - "port_map": {}, - "params": {"w": width * 1e-6, "l": length * 1e-6, "Nx": nf}, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "esd"], + symbol="ckt", + ports={"top": ["VDD"], "bottom": ["VSS"]}, + models=[{ + "language": "spice", + "name": "nmoscl_2", + "spice_type": "SUBCKT", + "library": "cornerMOSlv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["VDD", "VSS"], + }], +) def esd_nmos( width: float = 50.0, length: float = 0.5, nf: int = 10, - model: str = "nmoscl_2", layer_pwell: LayerSpec = "PWelldrawing", layer_activ: LayerSpec = "Activdrawing", layer_gatpoly: LayerSpec = "GatPolydrawing", @@ -211,7 +227,6 @@ def esd_nmos( width: Total width of the ESD device in micrometers. length: Gate length in micrometers. nf: Number of fingers. - model: Device model name. layer_pwell: P-well layer. layer_activ: Active region layer. layer_gatpoly: Gate polysilicon layer. @@ -357,20 +372,26 @@ def esd_nmos( port_type="electrical", ) - # Add VLSIR metadata - c.info["vlsir"] = { - "model": model, - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_moslv_mod.lib", - "port_order": ["VDD", "VSS"], - "port_map": {}, - "params": {"w": width * 1e-6, "l": length * 1e-6, "ng": nf}, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "tap"], + symbol="ckt", + ports={"left": ["1"], "right": ["2"]}, + models=[{ + "language": "spice", + "name": "ptap1", + "spice_type": "SUBCKT", + "library": "cornerRES.lib", + "sections": ["res_typ", "res_bcs", "res_wcs"], + "port_order": ["1", "2"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + }, + }], +) def ptap1( width: float = 1.0, length: float = 1.0, @@ -480,24 +501,26 @@ def ptap1( c.info["rows"] = rows c.info["cols"] = cols - # Add VLSIR metadata - c.info["vlsir"] = { - "model": "ptap1", + return c + + +@gf.cell( + tags=["IHP", "tap"], + symbol="ckt", + ports={"left": ["1"], "right": ["2"]}, + models=[{ + "language": "spice", + "name": "ntap1", "spice_type": "SUBCKT", - "spice_lib": "resistors_mod.lib", + "library": "cornerRES.lib", + "sections": ["res_typ", "res_bcs", "res_wcs"], "port_order": ["1", "2"], - "port_map": {}, "params": { - "w": width * 1e-6, - "l": length * 1e-6, + "w": "width * 1e-6", + "l": "length * 1e-6", }, - # TODO: Translate "rows, cols" - } - - return c - - -@gf.cell + }], +) def ntap1( width: float = 1.0, length: float = 1.0, @@ -618,20 +641,6 @@ def ntap1( c.info["rows"] = rows c.info["cols"] = cols - # Add VLSIR metadata - c.info["vlsir"] = { - "model": "ntap1", - "spice_type": "SUBCKT", - "spice_lib": "resistors_mod.lib", - "port_order": ["1", "2"], - "port_map": {}, - "params": { - "w": width * 1e-6, - "l": length * 1e-6, - }, - # TODO: Translate "rows, cols" - } - return c diff --git a/ihp/cells/resistors.py b/ihp/cells/resistors.py index 195bac2..1c67fd6 100644 --- a/ihp/cells/resistors.py +++ b/ihp/cells/resistors.py @@ -21,12 +21,27 @@ def add_rect( return ref -@gf.cell +@gf.cell( + tags=["IHP", "resistor", "poly"], + symbol="resistor", + ports={"left": ["1"], "right": ["2"], "bottom": ["bn"]}, + models=[{ + "language": "spice", + "name": "rsil", + "spice_type": "SUBCKT", + "library": "cornerRES.lib", + "sections": ["res_typ", "res_bcs", "res_wcs"], + "port_order": ["1", "2", "bn"], + "params": { + "w": "dx * 1e-6", + "l": "dy * 1e-6", + }, + }], +) 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", @@ -42,7 +57,6 @@ def rsil( 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. @@ -188,7 +202,6 @@ def rsil( # Metadata c.info.update( { - "model": model, "dy": dy, "dx": dx, "resistance": resistance, @@ -197,25 +210,30 @@ def rsil( } ) - # VLSIR simulation metadata - c.info["vlsir"] = { - "model": model, - "spice_type": "SUBCKT", - "spice_lib": "resistors_mod.lib", - "port_order": ["1", "2", "bn"], - "port_map": {"P1": "1", "P2": "2"}, - "params": {"w": dx * 1e-6, "l": dy * 1e-6, "m": 1}, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "resistor", "poly"], + symbol="resistor", + ports={"left": ["1"], "right": ["2"], "bottom": ["bn"]}, + models=[{ + "language": "spice", + "name": "rppd", + "spice_type": "SUBCKT", + "library": "cornerRES.lib", + "sections": ["res_typ", "res_bcs", "res_wcs"], + "port_order": ["1", "2", "bn"], + "params": { + "w": "dx * 1e-6", + "l": "dy * 1e-6", + }, + }], +) def rppd( dy: float = 0.5, dx: float = 0.5, resistance: float | None = None, - model: str = "rppd", layer_poly: LayerSpec = "PolyResdrawing", layer_heat: LayerSpec = "HeatResdrawing", layer_gate: LayerSpec = "GatPolydrawing", @@ -232,7 +250,6 @@ def rppd( 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. @@ -391,7 +408,6 @@ def rppd( # Metadata c.info.update( { - "model": model, "dy": dy, "dx": dx, "resistance": resistance, @@ -400,25 +416,30 @@ def rppd( } ) - # VLSIR simulation metadata - c.info["vlsir"] = { - "model": model, - "spice_type": "SUBCKT", - "spice_lib": "resistors_mod.lib", - "port_order": ["1", "3", "bn"], - "port_map": {"P1": "1", "P2": "3"}, - "params": {"w": dx * 1e-6, "l": dy * 1e-6, "m": 1}, - } - return c -@gf.cell +@gf.cell( + tags=["IHP", "resistor", "poly"], + symbol="resistor", + ports={"left": ["1"], "right": ["2"], "bottom": ["bn"]}, + models=[{ + "language": "spice", + "name": "rhigh", + "spice_type": "SUBCKT", + "library": "cornerRES.lib", + "sections": ["res_typ", "res_bcs", "res_wcs"], + "port_order": ["1", "2", "bn"], + "params": { + "w": "dx * 1e-6", + "l": "dy * 1e-6", + }, + }], +) def rhigh( dy: float = 0.96, dx: float = 0.5, resistance: float | None = None, - model: str = "rhigh", layer_poly: LayerSpec = "PolyResdrawing", layer_heat: LayerSpec = "HeatResdrawing", layer_gate: LayerSpec = "GatPolydrawing", @@ -436,7 +457,6 @@ def rhigh( 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. @@ -595,7 +615,6 @@ def rhigh( # Metadata c.info.update( { - "model": model, "dy": dy, "dx": dx, "resistance": resistance, @@ -604,16 +623,6 @@ def rhigh( } ) - # VLSIR simulation metadata - c.info["vlsir"] = { - "model": model, - "spice_type": "SUBCKT", - "spice_lib": "resistors_mod.lib", - "port_order": ["1", "3", "bn"], - "port_map": {"P1": "1", "P2": "3"}, - "params": {"w": dx * 1e-6, "l": dy * 1e-6, "m": 1}, - } - return c diff --git a/ihp/cells/rf_transistors.py b/ihp/cells/rf_transistors.py index 63b6b76..1e86adc 100644 --- a/ihp/cells/rf_transistors.py +++ b/ihp/cells/rf_transistors.py @@ -884,7 +884,26 @@ def _rf_mos_core( # --------------------------------------------------------------------------- # Public RF cell functions # --------------------------------------------------------------------------- -@gf.cell +@gf.cell( + tags=["IHP", "mos", "lv", "rf"], + symbol="nmos", + ports={"top": ["D"], "bottom": ["S"], "left": ["G"], "right": ["B"]}, + models=[{ + "language": "spice", + "name": "sg13_lv_nmos", + "spice_type": "SUBCKT", + "library": "cornerMOSlv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["D", "G", "S", "B"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + "ng": "nf", + "m": "m", + "rfmode": "1", + }, + }], +) def rfnmos( width: float = 1.0, length: float = 0.13, @@ -894,7 +913,6 @@ def rfnmos( met2_cont: bool = True, gat_ring: bool = True, guard_ring: str = "Yes", - model: str = "sg13_lv_nmos", ) -> Component: """Create an RF NMOS transistor. @@ -907,7 +925,6 @@ def rfnmos( met2_cont: Include Metal2-to-contact connections. gat_ring: Include gate ring around the transistor. guard_ring: Guard ring type: "Yes", "No", "U", or "Top+Bottom". - model: Device model name. Returns: Component with RF NMOS transistor layout. @@ -937,24 +954,29 @@ def rfnmos( is_pmos=False, is_hv=False, ) - c.info["vlsir"] = { - "model": "sg13_lv_nmos", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_moslv_mod.lib", - "port_order": ["d", "g", "s", "b"], - "port_map": {"D": "d", "G": "g", "S": "s"}, - "params": { - "w": width * 1e-6, - "l": length * 1e-6, - "ng": nf, - "m": m, - "rfmode": 1, - }, - } return c -@gf.cell +@gf.cell( + tags=["IHP", "mos", "lv", "rf"], + symbol="pmos", + ports={"top": ["D"], "bottom": ["S"], "left": ["G"], "right": ["B"]}, + models=[{ + "language": "spice", + "name": "sg13_lv_pmos", + "spice_type": "SUBCKT", + "library": "cornerMOSlv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["D", "G", "S", "B"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + "ng": "nf", + "m": "m", + "rfmode": "1", + }, + }], +) def rfpmos( width: float = 1.0, length: float = 0.13, @@ -964,7 +986,6 @@ def rfpmos( met2_cont: bool = True, gat_ring: bool = True, guard_ring: str = "Yes", - model: str = "sg13_lv_pmos", ) -> Component: """Create an RF PMOS transistor. @@ -977,7 +998,6 @@ def rfpmos( met2_cont: Include Metal2-to-contact connections. gat_ring: Include gate ring around the transistor. guard_ring: Guard ring type: "Yes", "No", "U", or "Top+Bottom". - model: Device model name. Returns: Component with RF PMOS transistor layout. @@ -1007,24 +1027,29 @@ def rfpmos( is_pmos=True, is_hv=False, ) - c.info["vlsir"] = { - "model": "sg13_lv_pmos", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_moslv_mod.lib", - "port_order": ["d", "g", "s", "b"], - "port_map": {"D": "d", "G": "g", "S": "s"}, - "params": { - "w": width * 1e-6, - "l": length * 1e-6, - "ng": nf, - "m": m, - "rfmode": 1, - }, - } return c -@gf.cell +@gf.cell( + tags=["IHP", "mos", "hv", "rf"], + symbol="nmos", + ports={"top": ["D"], "bottom": ["S"], "left": ["G"], "right": ["B"]}, + models=[{ + "language": "spice", + "name": "sg13_hv_nmos", + "spice_type": "SUBCKT", + "library": "cornerMOShv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["D", "G", "S", "B"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + "ng": "nf", + "m": "m", + "rfmode": "1", + }, + }], +) def rfnmos_hv( width: float = 1.0, length: float = 0.45, @@ -1034,7 +1059,6 @@ def rfnmos_hv( met2_cont: bool = True, gat_ring: bool = True, guard_ring: str = "Yes", - model: str = "sg13_hv_nmos", ) -> Component: """Create a high-voltage RF NMOS transistor. @@ -1047,7 +1071,6 @@ def rfnmos_hv( met2_cont: Include Metal2-to-contact connections. gat_ring: Include gate ring around the transistor. guard_ring: Guard ring type: "Yes", "No", "U", or "Top+Bottom". - model: Device model name. Returns: Component with HV RF NMOS transistor layout. @@ -1077,24 +1100,29 @@ def rfnmos_hv( is_pmos=False, is_hv=True, ) - c.info["vlsir"] = { - "model": "sg13_hv_nmos", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_moshv_mod.lib", - "port_order": ["d", "g", "s", "b"], - "port_map": {"D": "d", "G": "g", "S": "s"}, - "params": { - "w": width * 1e-6, - "l": length * 1e-6, - "ng": nf, - "m": m, - "rfmode": 1, - }, - } return c -@gf.cell +@gf.cell( + tags=["IHP", "mos", "hv", "rf"], + symbol="pmos", + ports={"top": ["D"], "bottom": ["S"], "left": ["G"], "right": ["B"]}, + models=[{ + "language": "spice", + "name": "sg13_hv_pmos", + "spice_type": "SUBCKT", + "library": "cornerMOShv.lib", + "sections": ["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"], + "port_order": ["D", "G", "S", "B"], + "params": { + "w": "width * 1e-6", + "l": "length * 1e-6", + "ng": "nf", + "m": "m", + "rfmode": "1", + }, + }], +) def rfpmos_hv( width: float = 1.0, length: float = 0.40, @@ -1104,7 +1132,6 @@ def rfpmos_hv( met2_cont: bool = True, gat_ring: bool = True, guard_ring: str = "Yes", - model: str = "sg13_hv_pmos", ) -> Component: """Create a high-voltage RF PMOS transistor. @@ -1117,7 +1144,6 @@ def rfpmos_hv( met2_cont: Include Metal2-to-contact connections. gat_ring: Include gate ring around the transistor. guard_ring: Guard ring type: "Yes", "No", "U", or "Top+Bottom". - model: Device model name. Returns: Component with HV RF PMOS transistor layout. @@ -1147,18 +1173,4 @@ def rfpmos_hv( is_pmos=True, is_hv=True, ) - c.info["vlsir"] = { - "model": "sg13_hv_pmos", - "spice_type": "SUBCKT", - "spice_lib": "sg13g2_moshv_mod.lib", - "port_order": ["d", "g", "s", "b"], - "port_map": {"D": "d", "G": "g", "S": "s"}, - "params": { - "w": width * 1e-6, - "l": length * 1e-6, - "ng": nf, - "m": m, - "rfmode": 1, - }, - } return c diff --git a/metadata_guide.md b/metadata_guide.md new file mode 100644 index 0000000..37a7c0c --- /dev/null +++ b/metadata_guide.md @@ -0,0 +1,31 @@ +# Cell Metadata Annotation Conventions + +## Tags +- First tag is the PDK name, using official casing: `"IHP"` +- Technical terms stay lowercase even if acronyms: `"mos"`, `"lv"`, `"hv"` +- Keep tags minimal: `["IHP", "mos", "lv"]` is sufficient, no need for `"transistor"` etc. +- Example: `tags=["IHP", "mos", "lv"]` + +## Ports (symbol layout) +- Use standard MOSFET symbol orientation: D top, S bottom, G left, B right +- Port names match the layout port names (uppercase for transistors): `"D"`, `"G"`, `"S"`, `"B"` +- Example: `ports={"top": ["D"], "bottom": ["S"], "left": ["G"], "right": ["B"]}` + +## Models +- `library` points to the **corner file** (e.g. `cornerMOSlv.lib`), not the model file — the corner file has the `.LIB`/`.ENDL` sections and includes the model file internally +- `sections` lists the base PVT corners from the corner file (e.g. `["mos_tt", "mos_ss", "mos_ff", "mos_sf", "mos_fs"]`) +- `port_order` uses symbol port names (uppercase), matching the positional order from the `.subckt` definition +- `params` values are **string expressions** over the function's kwargs (e.g. `"width * 1e-6"`) + +## Wrapper cells (e.g. rfcmim wrapping cmim) +- When a cell copies `c.info` from an inner cell (`c.info = inner.info`), the model name from the inner cell will overwrite the outer cell's identity +- Always reset `c.info["model"]` after copying: `c.info["model"] = "cap_rfcmim"` +- Check that labels and any other references to `model` are updated to use the correct name + +## Removed +- `model` parameter from function signature — was dead code (never referenced in body, vlsir dict hardcoded the name) +- `c.info["vlsir"]` block — replaced entirely by `@gf.cell()` kwargs + +**Why:** Moving metadata to decorator kwargs allows gfp2-server to extract it statically via AST parsing (no Python execution needed). + +**How to apply:** When converting any `@gf.cell` + `c.info["vlsir"]` pattern, follow these conventions. Study the actual spice corner files for correct `library`, `sections`, and `port_order`.