본문으로 바로가기

sd metal

category 기타(ETC)/단축키정리 2026. 11. 8. 22:52

;; ============================================================
;; [Environment Settings]
;; ============================================================
;; 1. Target Cell Name Settings (The skill works only for cells specified here)
;; (To apply without restriction to all cells, change to nil: defvar( MyTargetCells nil ) )
defvar( MyTargetCells  list("pmos2v" "nmos2v") )

;; 2. Layer Settings
;; 2-1. New metal layer to draw and reference point (existing S/D metal) layer
defvar( MyTargetMetalLayer list("METAL1" "drawing") )
defvar( MySndMetalLayer    list("METAL1" "drawing") )

;; 2-2. DIFF (Active) layer that determines the top/bottom length
;; (May be called "OD", "RX", "active", etc. depending on the PDK, so modify if it doesn't match)
defvar( MyDiffLayer        list("DIFF" "drawing") )

;; 3. PathSeg Width Setting
defvar( MyPathSegWidth 0.34 )
;; ============================================================

procedure( MyAddSDMetalPathSeg()
  let((cv selSet instMaster diffBox diffMinY diffMaxY sdXList uniqueSdXList lastX
       p1Master p2Master p1Top p2Top newSeg successCount orient centerX centerY)
    
    cv = geGetEditCellView()
    selSet = geGetSelSet()
    successCount = 0
    
    if( !selSet then
      printf(">>> [Error] No instances selected.\n")
      return(nil)
    )
    
    foreach( inst selSet
      if( inst~>objType == "inst" then
        ;; ★ Target Cell Name Filtering ★
        if( MyTargetCells && !member(inst~>cellName MyTargetCells) then
          printf(">>> [Skip] Instance '%s' (Cell: %s) is not in the target list.\n" inst~>name inst~>cellName)
        else
          orient = inst~>orient
          
          ;; Exclude 90-degree and 270-degree rotations (Only allow R0, MY, MX, R180)
          if( member(orient list("R0" "MY" "MX" "R180")) then
            instMaster = inst~>master
            diffBox = nil
            sdXList = nil
            
            ;; --------------------------------------------------------
            ;; Step 1. Get the full Bounding Box of the DIFF layer from the original cell (Master)
            ;; --------------------------------------------------------
            foreach( shape instMaster~>shapes
              if( shape~>lpp == MyDiffLayer && (shape~>objType == "rect" || shape~>objType == "polygon") then
                if( !diffBox then
                  diffBox = shape~>bBox
                else
                  ;; If there are multiple DIFF pieces, merge them into the largest bounding area
                  diffBox = list(
                    list( min(caar(diffBox) caar(shape~>bBox)) min(cadar(diffBox) cadar(shape~>bBox)) )
                    list( max(caadr(diffBox) caadr(shape~>bBox)) max(cadadr(diffBox) cadadr(shape~>bBox)) )
                  )
                )
              )
            )
            
            if( !diffBox then
              printf(">>> [Warning] DIFF layer not found in '%s'. Check 'MyDiffLayer' setting. Skipping.\n" inst~>name)
            else
              diffMinY = cadar(diffBox)
              diffMaxY = cadadr(diffBox)
              
              ;; --------------------------------------------------------
              ;; Step 2. Find existing Source/Drain metals and extract X coordinates (horizontal position)
              ;; --------------------------------------------------------
              foreach( shape instMaster~>shapes
                if( shape~>lpp == MySndMetalLayer && (shape~>objType == "rect" || shape~>objType == "polygon") then
                  centerY = (cadar(shape~>bBox) + cadadr(shape~>bBox)) / 2.0
                  
                  ;; Trick logic: To avoid irrelevant metals such as gate metals, 
                  ;; consider only metals whose Y center point is inside the DIFF (Active) region as S/D metals.
                  if( centerY > diffMinY && centerY < diffMaxY then
                    centerX = (caar(shape~>bBox) + caadr(shape~>bBox)) / 2.0
                    sdXList = cons(centerX sdXList)
                  )
                )
              )
              
              if( !sdXList then
                printf(">>> [Warning] S/D Metal not found inside DIFF region of '%s'. Skipping.\n" inst~>name)
              else
                ;; --------------------------------------------------------
                ;; Step 3. Sort X coordinates and remove duplicates (for multi-finger support)
                ;; --------------------------------------------------------
                ;; (If multiple contacts are placed, the same X coordinate is collected multiple times, so combine them into one)
                sdXList = sort( sdXList 'lessp )
                uniqueSdXList = nil
                lastX = -10000.0
                
                foreach( x sdXList
                  if( abs(x - lastX) > 0.001 then
                    uniqueSdXList = cons(x uniqueSdXList)
                    lastX = x
                  )
                )
                
                ;; --------------------------------------------------------
                ;; Step 4. Draw a thick PathSeg for each extracted finger
                ;; --------------------------------------------------------
                foreach( x uniqueSdXList
                  ;; Master-based start and end points (from bottom to top of DIFF)
                  p1Master = list(x diffMinY)
                  p2Master = list(x diffMaxY)
                  
                  ;; Transform coordinates according to the current instance's location/rotation state
                  p1Top = dbTransformPoint( p1Master inst~>transform )
                  p2Top = dbTransformPoint( p2Master inst~>transform )
                  
                  ;; Create PathSeg (apply truncate property to cut off cleanly without sticking out of DIFF)
                  newSeg = dbCreatePathSeg( cv MyTargetMetalLayer p1Top p2Top MyPathSegWidth "truncate" "truncate" )
                  
                  ;; Attach to the instance so they move together later
                  if( newSeg then leAttachFig( newSeg inst ) )
                )
                
                successCount = successCount + 1
              )
            )
          )
        )
      else
        printf(">>> [Skip] Selected object is not an instance. Skipping.\n")
      )
    )
    
    printf(">>> [Done] Added thick S/D METAL1 to %d instance(s).\n" successCount)
    t
  )
)

;; F7 Bindkey Assignment
hiSetBindKey("Layout" "<Key>F7" "MyAddSDMetalPathSeg()")

printf(">>> [Loaded] Source/Drain Metal PathSeg script loaded (F7)\n")

'기타(ETC) > 단축키정리' 카테고리의 다른 글

bus route  (0) 2026.11.08
r_t key  (0) 2026.11.08
poly ext  (0) 2026.11.08
quick align  (0) 2026.11.08