1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
###############################################################################
# Copyright (c) 2015-2024 by Altair Engineering, Inc.
# All rights reserved.
#
# Altair Engineering, Inc. makes this software available as part of the Vision
# tool platform.  As long as you are a licensee of the Vision tool platform
# you may make copies of the software and modify it to be used within the
# Vision tool platform, but you must include all of this notice on any copy.
# Redistribution without written permission to any third party, with or
# without modification, is not permitted.
# Altair Engineering, Inc. does not warrant that this software is error free
# or fit for any purpose.  Altair Engineering, Inc. disclaims any liability for
# all claims, expenses, losses, damages and costs any user may incur as a
# result of using, copying or modifying the software.
# =============================================================================
#   @plugin
#       Run ESD Checks
#   @namespace
#       ESD
#   @section
#       Analyze the Loaded Database
#   @description
#       Load the ESD checks.
#   @test
#       ModuleTest
#   @files
#       esd/runesd.tcl
#       esd/utils.tcl
#       esd/check01.tcl
#       esd/check02.tcl
#       esd/check03.tcl
#       esd/check04.tcl
#       esd/check05.tcl
#       esd/check06.tcl
#       esd/check07.tcl
#       esd/check08.tcl
#       esd/check09.tcl
#       esd/check10.tcl
#   @example
#       demo/api/esd/testcase01.sp
#       demo/api/esd/testcase02.sp
#       demo/api/esd/testcase03.sp
#       demo/api/esd/testcase04.sp
#       demo/api/esd/testcase05.sp
#       demo/api/esd/testcase06.sp
#       demo/api/esd/testcase07.sp
#       demo/api/esd/testcase08.sp
#       demo/api/esd/testcase09.sp
#       demo/api/esd/testcase10.sp
#   @cmdline
#       -hspice @example[0]
#       -userware @files[0]
#   @tag
#       zdb gui spice
###############################################################################


##
# Load utility procedures used by all checks.
#
source [file join [file dirname [info script]] "utils.tcl"]


##
# Set the name for the menu and result widget.
#
set ESD(name) "ESD Checks"


# =============================================================================
# Init - Initialize the plugin.
# =============================================================================
#
proc ESD:Init {} {
    global ESD

    set ESD(MenuEntries) {}

    foreach {
        check   title      \
                description
    } {
        Check01 "Input to MOS Gate Protection" \
                "check that an ESD resistor is connected between toplevel input\
                 port and gate pin"
        Check02 "Supply Port Protection" \
                "power supply ports must be protected by a protection cell"
        Check03 "Resistor Protection of MOS devices" \
                "gate pins should not be connected to power/ground nets through\
                 a resistor less than a certain value"
        Check04 "Input Pin connectivity" \
                "toplevel input ports can only be connected to gates and diodes"
        Check05 "I/O Port Protection with NMOS and Resistor" \
                "MOS gates connected to an I/O port must be protected with a\
                 protection circuit"
        Check06 "Stacked NFETs and Diode String" \
                "NMOS connected to I/O ports must be stacked and a diode string\
                 should be used for protection"
        Check07 "I/O Port Diode Protection" \
                "I/O ports must be protected by a single down diode and a\
                 single up diode"
        Check08 "I/O Port NMOS and Diode Protection" \
                "I/O ports must be protected by a single down diode and a NMOS."
        Check09 "ESD Protection for Low Voltage-MOS" \
                "low-voltage gates connected to toplevel ports should be\
                 protected by an ESD diode, zener diode and a resistor"
        Check10 "ESD Protection for Input Gates" \
                "gates connected to toplevel ports must be protected with HBM,\
                 CDM diodes and a resistor"
    } {
        lappend ESD(MenuEntries) $check $title $description
    }

    ##
    # Add a command to the menu for each check.
    #
    set cwd [file dirname [info script]]
    foreach {check title description} $ESD(MenuEntries) {
        source [file join $cwd [string tolower $check].tcl]
        gui menu command             \
            [list $ESD(name) $title] \
            [list ESD:_runCheck $ESD(name) $check $title $description]
    }

    ##
    # Add a menu item to close the result widget.
    #
    gui menu separator [list $ESD(name)] -sepId "ESD_SEP1"
    gui menu command                       \
        [list $ESD(name) "Run all Checks"] \
        [list ESD:_runAllChecks]
    gui menu separator [list $ESD(name)] -sepId "ESD_SEP2"
    gui menu command                            \
        [list $ESD(name) "Clear Result Window"] \
        [list ESD:_clearResultWindow $ESD(name) {}]
    gui menu command                            \
        [list $ESD(name) "Close Result Window"] \
        [list ESD:_hideResultWindow $ESD(name)]

    ##
    # Clear the result window if the database was changed.
    #
    gui database registerChangedCallback \
        [list ESD:_clearResultWindow $ESD(name)]
}


# =============================================================================
# Finit - Finalize the plugin.
# =============================================================================
#
proc ESD:Finit {} {
    global ESD

    foreach {check title description} $ESD(MenuEntries) {
        gui menu removeEntry [list $ESD(name) $title]
    }
    gui menu removeSeparator [list $ESD(name)] "ESD_SEP1"
    gui menu removeEntry     [list $ESD(name) "Run all Checks"]
    gui menu removeSeparator [list $ESD(name)] "ESD_SEP2"
    gui menu removeEntry     [list $ESD(name) "Clear Result Window"]
    gui menu removeEntry     [list $ESD(name) "Close Result Window"]

    if {[gui window exists $ESD(name)]} {
        gui window removeCustomWidget $ESD(name)
    }
    gui database removeChangedCallback "ESD:_clearResultWindow"

    array unset ESD
}


# -----------------------------------------------------------------------------
# _hideResultWindow - Display the oidList forming an ESD circuit in the Cone.
# -----------------------------------------------------------------------------
#
proc RunEsd:_hideResultWindow {name} {
    gui window removeCustomWidget $name
}


# -----------------------------------------------------------------------------
# _showOidList - Display the oidList forming an ESD circuit in the Cone.
# -----------------------------------------------------------------------------
#
proc ESD:_showOidList {w} {
    set item [$w focus]
    if {[$w parent $item] != {}} {
        set oidList [$w item $item -values]
        gui window show Cone
        gui cone load $oidList
        gui cone zoom fullfit
    }
}


# -----------------------------------------------------------------------------
# _invoke - Run the given check and show the result.
# -----------------------------------------------------------------------------
#
proc ESD:_invoke {name check title description} {
    ##
    # Get the currently loaded database.
    #
    set db [gui database get]

    ##
    # Return if the database is empty.
    #
    if {$db == {}} {
        zmessage print ERR "No Database Loaded."
        return
    }

    ##
    # Create a custom treeview widget to display the results.
    #
    if {![gui window exists $name]} {
        set customWidget [gui window insertCustomWidget \
                            -pluginNamespace "ESD" \
                            $name]
        ttk::treeview $customWidget.result \
            -show tree \
            -yscrollcommand [list $customWidget.y set]
        ttk::scrollbar $customWidget.y \
            -orient  vertical \
            -command [list $customWidget.result yview]
        grid $customWidget.result -row 0 -column 0 -sticky news
        grid $customWidget.y      -row 0 -column 1 -sticky ns
        grid rowconfigure    $customWidget 0 -weight 1
        grid columnconfigure $customWidget 0 -weight 1
        $customWidget.result tag configure OK  -foreground green
        $customWidget.result tag configure BAD -foreground red
        bind $customWidget.result <Double-1> {ESD:_showOidList %W}
    } else {
        set customWidget [gui window path $name]
    }

    ##
    # Run the check and assign the result to a variable.
    #
    set resultList [ESD:$check $db]

    ##
    # Either delete all children or create the tree item for this check.
    #
    set id $title
    if {[$customWidget.result exists $id]} {
        $customWidget.result delete [$customWidget.result children $id]
    } else {
        $customWidget.result insert {} end -id $id -text "$title ($description)"
    }

    ##
    # Add the result to the tree view.
    #
    foreach {
        start oidList description
    } $resultList {
        if {$description eq ""} {
            set description "OK"
            set tag OK
        } else {
            set tag BAD
        }
        lappend oidList $start
        $customWidget.result insert $id end \
            -text   "${start}: $description"  \
            -values $oidList \
            -tag    $tag
    }
}


# -----------------------------------------------------------------------------
# _runCheck -
# -----------------------------------------------------------------------------
#
proc ESD:_runCheck {name check title description} {
    zprogress begin

    ESD:_invoke $name $check $title $description

    zprogress end
}


# -----------------------------------------------------------------------------
# _runAllChecks -
# -----------------------------------------------------------------------------
#
proc ESD:_runAllChecks {} {
    global ESD

    zprogress begin

    set count [expr {[llength $ESD(MenuEntries)] / 3}]

    set i 0
    foreach {check title description} $ESD(MenuEntries) {
        zprogress push $title [expr {double([incr i]) / $count}]

        ESD:_invoke $ESD(name) $check $title $description

        if {[zprogress pop]} {
            break
        }
    }


    zprogress end
}


# -----------------------------------------------------------------------------
# _clearResultWindow -
# -----------------------------------------------------------------------------
#
proc ESD:_clearResultWindow {name db} {
    if {[gui window exists $name]} {
        set customWidget [gui window path $name]
        $customWidget.result delete [$customWidget.result children {}]
    }
}


# =============================================================================
# Call the initialization procedure.
# =============================================================================
#
ESD:Init