mirror of https://github.com/VLSIDA/OpenRAM.git
sky130: use special_nfet_01v8 model for sub-0.42um nfets
The sky130 magic techfile splits nfet extraction on device width: device msubcircuit sky130_fd_pr__nfet_01v8 nfet,scnfet ... w>=0.42 device msubcircuit sky130_fd_pr__special_nfet_01v8 scnfet ... w<0.42 ptx always emitted spice["nmos"], so every gate built from a minimum-width device (drc["minwidth_tx"] = 0.36) was netlisted as sky130_fd_pr__nfet_01v8 while magic extracted it as sky130_fd_pr__special_nfet_01v8. netgen then reported a device class mismatch in each such cell: Circuit 1: sky130_fd_pr__special_nfet_01v8 (1) | Circuit 2: (no matching element) Circuit 1: (no matching element) | Circuit 2: sky130_fd_pr__nfet_01v8 (1) The signed-off macros shipped in sky130A/libs.ref/sky130_sram_macros use special_nfet_01v8 at this geometry, so this restores the naming those were built with. ptx now asks the technology for a narrow-device model, keyed by width. Technologies that declare no such model are unaffected, and there is no equivalent split for pfets so only the nmos is declared. After this change pinv and pinv_dec report "Netlists match uniquely" where they previously mismatched. Verified with ngspice that special_nfet_01v8 resolves through sky130.lib.spice, so characterization is unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FcKSuKSchDEd7MqT8AffpN
This commit is contained in:
parent
ed369f1af4
commit
1123f733bd
|
|
@ -116,12 +116,32 @@ class ptx(design):
|
|||
# but this may be uncommented for debug purposes
|
||||
# self.DRC()
|
||||
|
||||
def get_model_name(self):
|
||||
"""
|
||||
Return the device model name for this transistor's width.
|
||||
|
||||
Some technologies model narrow devices with a separate model. In
|
||||
sky130, an nfet narrower than 0.42um is extracted as
|
||||
sky130_fd_pr__special_nfet_01v8 rather than sky130_fd_pr__nfet_01v8
|
||||
(see the "device msubcircuit" rules in sky130A.tech), so the netlist
|
||||
must use the same name or LVS reports a device class mismatch on
|
||||
every gate built from a minimum-width device.
|
||||
"""
|
||||
narrow_model = spice.get("{}_narrow".format(self.tx_type))
|
||||
narrow_width = spice.get("{}_narrow_max_width".format(self.tx_type))
|
||||
if narrow_model and narrow_width and self.tx_width < narrow_width:
|
||||
return narrow_model
|
||||
|
||||
return spice[self.tx_type]
|
||||
|
||||
def create_netlist(self):
|
||||
pin_list = ["D", "G", "S", "B"]
|
||||
if self.tx_type == "nmos":
|
||||
body_dir = "GROUND"
|
||||
else:
|
||||
body_dir = "POWER"
|
||||
|
||||
self.model_name = self.get_model_name()
|
||||
dir_list = ["INOUT", "INPUT", "INOUT", body_dir]
|
||||
self.add_pin_list(pin_list, dir_list)
|
||||
|
||||
|
|
@ -133,7 +153,7 @@ class ptx(design):
|
|||
self.channel_length = drc("minlength_channel")
|
||||
if cell_props.ptx.model_is_subckt:
|
||||
# sky130
|
||||
main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
||||
main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(self.model_name,
|
||||
self.mults,
|
||||
self.tx_width,
|
||||
self.channel_length)
|
||||
|
|
@ -142,7 +162,7 @@ class ptx(design):
|
|||
area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(perimeter_sd,
|
||||
area_sd)
|
||||
else:
|
||||
main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
|
||||
main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(self.model_name,
|
||||
self.mults,
|
||||
self.tx_width,
|
||||
self.channel_length)
|
||||
|
|
@ -164,12 +184,12 @@ class ptx(design):
|
|||
self.tx_width,
|
||||
self.channel_length)
|
||||
elif cell_props.ptx.model_is_subckt:
|
||||
self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2}u l={3}u".format(spice[self.tx_type],
|
||||
self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2}u l={3}u".format(self.model_name,
|
||||
self.mults,
|
||||
self.tx_width,
|
||||
self.channel_length)
|
||||
else:
|
||||
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
|
||||
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(self.model_name,
|
||||
self.mults,
|
||||
self.tx_width,
|
||||
self.channel_length)
|
||||
|
|
|
|||
|
|
@ -711,6 +711,14 @@ drc.add_enclosure("m5",
|
|||
spice = {}
|
||||
spice["nmos"] = "sky130_fd_pr__nfet_01v8"
|
||||
spice["pmos"] = "sky130_fd_pr__pfet_01v8"
|
||||
|
||||
# An nfet narrower than 0.42um is a different device in sky130: magic
|
||||
# extracts it as sky130_fd_pr__special_nfet_01v8, so the netlist has to use
|
||||
# that name below the threshold or netgen reports a device class mismatch.
|
||||
# See the "device msubcircuit" lines in sky130A.tech. There is no equivalent
|
||||
# split for pfets, so only the nmos is declared here.
|
||||
spice["nmos_narrow"] = "sky130_fd_pr__special_nfet_01v8"
|
||||
spice["nmos_narrow_max_width"] = 0.42
|
||||
spice["power"]="vccd1"
|
||||
spice["ground"]="vssd1"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue