• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Community Forums
  2. Custom IC SKILL
  3. Callback Code Not Working as Intended

Stats

  • Locked Locked
  • Replies 8
  • Subscribers 143
  • Views 12798
  • Members are here 0
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Callback Code Not Working as Intended

Ynishant
Ynishant over 3 years ago

Hi,

    I've been scratching my head over this for a little over a day and I can't seem to explain the behavior I'm seeing. For some background, I'm fairly new to SKILL and I've been creating a pCell for a MIM. The pCell, callbacks, and CDF all seem to be working well so far, however, in the callback I'm checking a condition and setting a CDF value based on my result. So, I want to check if the W and L of the cap is over 30 um, and if it is, I'd like to do another area check and then modify the cap layout based on that result. The code snippet below shows the current callback code. Now, the same snippet works perfectly fine and as intended in the pCell, but fails on two conditions in the callback!  

procedure( mim_cb(paramName)
        prog((value w l c ratio area num_horiz_strips num_vertical_strips sp_h sp_v remove_horiz waffle w_n l_n)

         ; Load values
         l = cdfParseFloatString(cdfgData~>Length~>value)
         w = cdfParseFloatString(cdfgData~>Width~>value)
         c = cdfParseFloatString(cdfgData~>c~>value)
         ratio = cdfParseFloatString(cdfgData~>aspect_ratio~>value)
         m = cdfParseFloatString(cdfgData~>m~>value)
         remove_horiz = cdfParseFloatString(cdfgData~>rem_h_strip~>value)
         num_horiz_strips = cdfParseFloatString(cdfgData~>n_horiz_strips~>value)
         num_vertical_strips = cdfParseFloatString(cdfgData~>n_vertical_strips~>value)

         w_n = w*1.0e6
         l_n = l*1.0e6
         warn("w_n %f" w_n)
         warn("l_n %f" l_n)


         if( (w_n>=30)||(l_n>=30) then
               if( (w_n*l_n) >= 360.0 then
                      waffle = "yes"
               else
                      waffle = "no"
          )
          else
               warn("Condition Satisfied w or l <=30")
               if( (w_n*l_n)>400.0 then
                      waffle = "yes"
               else
                      waffle = "no"
                )

           ) ; end of main if

) ; end of prog

); end of procedure

Regards,

Nishant. 

  • Cancel
  • Andrew Beckett
    Andrew Beckett over 3 years ago

    Your callback code doesn't really do anything. It sets a variable called waffle (and then doesn't do anything with that) but I don't see it updating any CDF parameters. What are you expecting it to do or what is going wrong?

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Ynishant
    Ynishant over 3 years ago in reply to Andrew Beckett

    Hi Andrew,

                     The portion of the code I pasted in my original message is only a snippet. The callback code in its entirety is copy-pasted below. It's an updated version that seems to work, but I just can't figure out why it works and it's driving me nuts. I can't seem to find a way to attach a file or paste the code in a manner that makes it more readable. Perhaps you can recommend a better way to paste code here and I can give it another go.  

                      Oh, and to clarify what's going wrong: When I enter W = 30u and L = 12u, the pCell code fails - i.e. It doesn't draw what it's supposed to draw. That's the only condition it fails on!

    Regards,

    Nishant. 

    Note from moderator: reformatted code to make it easier to read...

    procedure(mim_m2cs_init(cdfgData)
      mim_cb('Width)
     )
    
    ;; This is the common init/CB procedure used for the MIM caps
    procedure(mim_cb(paramName)
      prog(value(w l c ratio area num_horiz_strips num_vertical_strips sp_h sp_v remove_horiz waffle)
           
           ; Load values
           l = cdfParseFloatString(cdfgData~>l~>value)
           w = cdfParseFloatString(cdfgData~>w~>value)
           c = cdfParseFloatString(cdfgData~>c~>value)
           ratio = cdfParseFloatString(cdfgData~>aspect_ratio~>value)
           m = cdfParseFloatString(cdfgData~>m~>value)
           remove_horiz = cdfParseFloatString(cdfgData~>rem_h_strip~>value)
           num_horiz_strips = cdfParseFloatString(cdfgData~>n_horiz_strips~>value)
           num_vertical_strips = cdfParseFloatString(cdfgData~>n_vertical_strips~>value
                                                    )
           
           
           waffle = waffle_or_no(w l)
           ;warn("Waffle Status %d" waffle)
           
           
           ;warn(sprintf( nil "Initial Values: w=%g l=%g c=%g ratio=%g" w l c ratio))
           ; Calculate the number of vertical and horizontal strips if the cap area is >= 400 um^2
           if(waffle == "no"
               then
                   
                   area = 100
                   num_horiz_strips = 0
                   num_vertical_strips = 0
                   
               else
                   num_horiz_strips = mim_calc_n_strips(l)
                   num_vertical_strips = mim_calc_n_strips(w)
                   
                   ; Calculate the horizontal and vertical spacing
                   sp_h = mim_calc_bar_spacing(l num_horiz_strips)
                   sp_v = mim_calc_bar_spacing(w num_vertical_strips)
                   
                   ;Calculate the area
                   area = mim_measure_m3_area(w l num_horiz_strips num_vertical_strips sp_h sp_v)
                   
              )
            ; end of if 
           
           if(remove_horiz > 0
               then
                   ; force the number of strips to be removed to be <=2 
                   remove_horiz = mim_check_number_removals(remove_horiz)
                   num_horiz_strips = num_horiz_strips - remove_horiz
                   ; Calculate the horizontal and vertical spacing
                   sp_h = mim_calc_bar_spacing(l num_horiz_strips)
                   ;Re-Calculate the area
                   area = mim_measure_m3_area(w l num_horiz_strips num_vertical_strips sp_h sp_v)
                   
              )
           ; Do final value chacks
           l = mim_check_dim(l)
           w = mim_check_dim(w)
           ;adjust the ratio according to whichever dimension is bigger
           ratio = max(w l) / min(w l)
           ;warn(sprintf( nil "Initial Values: w=%g l=%g c=%g ratio=%g" w l c ratio))
           
           ; Do final capacitance calculation
           c = mim_calc_cap(w l m)
           
           ; Write back to form
           cdfgData~>l~>value = aelSuffixNotation(l)
           cdfgData~>w~>value = aelSuffixNotation(w)
           cdfgData~>c~>value = aelSuffixNotation(c)
           cdfgData~>aspect_ratio~>value = aelSuffixNotation(ratio)
           cdfgData~>m3_density~>value = aelSuffixNotation(area)
           cdfgData~>n_horiz_strips~>value = aelSuffixNotation(num_horiz_strips)
           cdfgData~>n_vertical_strips~>value = aelSuffixNotation(num_vertical_strips)
           cdfgData~>rem_h_strip~>value = aelSuffixNotation(remove_horiz)
          )
     )
    procedure(waffle_or_no(w l)
      let((waffle
           cap_area
           scale
           w_n
           l_n
          )
        scale = 1000000.0
        cap_area = w * scale * (l * scale)
        w_n = w * scale
        l_n = l * scale
        if(cap_area <= 400.0
            then
                if(((w_n > 30) && (l_n > 12)) || ((l_n > 30) && (w_n > 12))
                    then
                        waffle = 1
                    else
                        waffle = 0
                   )
            else
                waffle = 1
           )
        
        
        waffle ; return the waffle status
       )
     )
    
    procedure(mim_check_number_removals(value)
      let((max_removals
          )
        max_removals = 1
        if(max(value max_removals) > 1
            then
                value = max_removals
           )
        
        value ; return value
       )
      
     )
    
    ;; Helper function to check W & L dimenstions
    procedure(mim_check_dim(value)
      let((min_value
           max_value
          )
        ; setting the max width to 80 um and the min width to 5 um for now; Same for length
        min_value = 5e-06
        max_value = 8e-05
        if(max(value max_value) > max_value
            then
                warn("Max dimension is 80um")
                value = max_value
           )
        if(min(value min_value) < min_value
            then
                warn("Min dimension is 5.0um")
                value = min_value
           )
        
        ; finally force the value to a 0.1 um grid
        ;value = round(value*10)/10.0
        
        value ; return value for the procedure
       ) ;end of let
      
     )
    
    
    ; Procedure to calculate the number of horizontal or vertical strips in a MIM
    procedure(mim_calc_n_strips(value)
      let((n_horiz_strips
           n_vertical_strips
           hole_x_min
           bar_w
          )
        ; This is the width of the strip 
        bar_w = 2.5
        scale = 1000000.0
        ; This is the minimum size of the hole
        hole_x_min = 3.0
        n_strips = floor(((value * scale) + hole_x_min) / (bar_w + hole_x_min))
        
        n_strips
       )
     )
    
    ; Procedure to calculate the bar-bar spacing
    procedure(mim_calc_bar_spacing(dimension num_strips)
      let((spacing
           bar_w
          )
        bar_w = 2.5
        scale = 1000000.0
        spacing = (float(dimension * scale) - (bar_w * num_strips)) / (num_strips - 1)
        
        spacing
       )
     )
    
    ;; Helper function to calculate the M3 Density
    procedure(mim_measure_m3_area(w l num_h_strips num_v_strips width_spacing length_spacing)
      let((top_m_area
           hole_area
           num_holes
           scale
           strip_width
           m3_area
           density
          )
        ; Factor to sure everything is not in microns for the area calculations 
        scale = 1000000.0
        ; The strip width in the layout is set to a standard 2.5 um
        strip_width = 2.5
        top_m_area = w * scale * (l * scale)
        num_holes = (num_h_strips - 1) * (num_v_strips - 1)
        hole_area = num_holes * width_spacing * length_spacing
        m3_area = top_m_area - hole_area
        density = (m3_area / top_m_area) * 100.0
        density ; return value
        
       )
     )
    
    ;; Helper function to calculate capacitance value
    procedure(mim_calc_cap(w l m)
      let((area
           perim
           ca
           cp
           dx
           cap_ffmm
           perim_f
           total_cap_value
          )
        
        ;dx is the factor that accounts for the mask bias
        ;cap_ffmm is the ff/mm capacitance factor
        ;perim_f is the fringing capacitance parameter 
        dx = -1.2e-07
        cap_ffmm = 0.00135
        perim_f = 1.5e-10
        area = (w + dx) * (l + dx)
        perim = 2 * (w + dx + (l + dx))
        
        ca = area * cap_ffmm
        cp = perim * perim_f
        total_cap_value = m * (ca + cp)
        
        total_cap_value ; This is the return value for the procedure
       )
     )
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 3 years ago in reply to Ynishant

    I reformatted the code above (I have an internal tool that will reformat SKILL code to indent it somewhat sensibly). In general one approach I often use is put the code in a file with a ".txt" suffix and then open that file from a web browser and then copy and paste from there. That said, I'm on a Mac - so your mileage may vary - normally I don't have too much trouble pasting code.

    Your description of the problem though isn't really very clear. You've posted the callback code, but then said:

    Ynishant said:
    Oh, and to clarify what's going wrong: When I enter W = 30u and L = 12u, the pCell code fails - i.e. It doesn't draw what it's supposed to draw. That's the only condition it fails on!

    So you've said it's failing in the pCell code, which you've not shared. Maybe you meant the callback code, but that doesn't have anything to do with drawing. If it's the callback that's failing, please specify the values of the other CDF parameters that trigger the failure (rather than me trying to work out what you really meant) - there are values for c, ratio, m, rem_h_strip, n_horiz_strips and n_vertical_strips also involved as well as w and l. 

    If it's a problem with the Pcell code, then I guess it would be necessary to see the Pcell code too.

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Ynishant
    Ynishant over 3 years ago in reply to Andrew Beckett

    Hi Andrew, 

                     Thanks for the code pasting tip! Looking at the formatted code you've pasted has also given me some ideas on how to format my code to make it more readable (adding a newline after each local parameter value after the "let" really helps). I realize that I mentioned the pCell code but didn't include it. Fair enough. I didn't do a good job explaining exactly why and how the code was failing and I agree that including just some code doesn't help you help me. So, here's a brief overview:

    * I created a pCell for a simple MM cap. The cap has two modes - for a total cap area below a certain value, the connecting metal layer is a solid block of metal, for cap areas above a certain value the top metal is waffled or broken into horizontal and vertical strips

    * In the callback code, I run some checks to see if the cap needs to be waffled (in the "waffle_yes_or_no" procedure). I'm doing this because I'm displaying metal density and the number of horizontal or vertical strips in the cap in the parameter display window. This is vital, as the end user may decide to reduce the number of horizontal strips to meet metal density rules.

    * I run the identical waffle check in the main pCell code as will become clear below. Now, I'm doing this because I don't really want to create an extra cdf param or pass the waffle variable to the pCell. Since I'm very new to SKILL, I don't want to mess with creating global variables and passing values between compiled and uncompiled SKILL files. 

    * If I run the pCell code on it's own, i.e. if I just load the pCell skill file through the CIW into a library (load "pCell_code.il"). Everything works fine and the cap gets waffled when specified and everything's good with the world. 

    * If I run the entire packaged pCell with the callbacks, the CDF, and the pCell code, two conditions cause the layout to draw but not as intended. When the W and L values are set to 30 and 12 respectively, the pCell draws the cap, but without the metal3 layer. I did some debugging by including some warn statements and it turns out that the waffle check in the callback says that the cap shouldn't be waffled, while the check in the pCell says it should! The code is identical, so why is the same check giving me different results?  

    If you'd like to run the entire pCell with the CDF I can include that too. But the pCell code is pasted below with the suspect section highlighted.

    Regards,

    Nishant. 

    ;; Cap Waffle
    ;; Nishant V.01 03/07/2022
    
    strLibName = "MIM_Pcell_Final"
    strCellName = "cmim1p35_2"
    
    pcDefinePCell(list(ddGetObj(strLibName), strCellName, "layout"),
    
    ;Define default pcell parameter values
    (
    (w "string" "15u")
    (l "string" "15u")
    (c "string" "1.620pF")
    (m "string"   "1")
    (n_horiz_strips	"string"  "0")
    (n_vertical_strips	"string"  "0")
    (ablb  "boolean" t)
    ;(s_via "string" "1.5u")  ; Min spacing between vias, removing it for now because it's calculated
    );end of default values
    
    let((scale 
    	MBOT VIA VIA2 MTOP MTOP2 CTM DUM TEXT ABLB
    	num_horiz_strips num_vertical_strips bar_w hole_x_min w_VIA sp_h sp_v
            enc_VIA_MTOP w_MTOP l_MTOP enc_VIA_CTM enc_CTM_DUM enc_CTM_MBOT enc_VIA2_MTOP2 enc_ABLB_MBOT
            R_tmp R_ref offset_var offset_base num_vertical_vias num_horiz_vias via_pitch_y R_tmp1 via_pitch_x
            x y bet_via_spacing bar_offset off_via_spacing waffle s_via cap_area
    	)
    
    	; Define the layers
    	MBOT   = list("metal2"   "drawing")
    	VIA    = list("via2"     "drawing")
    	VIA2   = list("via3"     "drawing")
    	MTOP   = list("metal3"   "drawing")
    	MTOP2  = list("metal4"   "drawing")
    	CTM    = list("topmm"    "drawing") 
    	DUM    = list("cap2fF"   "drawing")
    	TEXT   = list("text"     "drawing")
    	ABLB   = list("ablb"     "drawing")
    	
    	
    	enc_ABLB_MBOT = 2.0
    	enc_CTM_MBOT = 1.0
    	enc_CTM_DUM  = 0.1
            enc_VIA_MTOP = 1.06
            enc_VIA2_MTOP2 = 0.5
            enc_VIA_CTM  = 1.06 
    	
    	; parameters needed
    	scale 		= 1e6
    	l           = evalstring(l)*scale
    	w           = evalstring(w)*scale
    	num_horiz_strips = evalstring(n_horiz_strips)
    	num_vertical_strips = evalstring(n_vertical_strips)
    	
    	s_via       = 1.5
    	bar_w       = 2.5
    	hole_x_min  = 3.0
    	sp 	    = hole_x_min
    	w_VIA 	    = 0.38
    	
    	; Figure out exact size of top-plate based on enclosures
    	enc_VIA_MTOP = enc_VIA_CTM ; ceiling((_tp/*bar_w-w_VIA)/2)
    	w_MTOP = ceiling(w + 2*(enc_VIA_MTOP - enc_VIA_CTM))
    	l_MTOP = ceiling(l + 2*(enc_VIA_MTOP - enc_VIA_CTM))
    	
    	offset_base = enc_VIA_MTOP - enc_VIA_CTM
    	offset_var = offset_base
    	
    	;create shapes
    	R_ref = rodCreateRect(
    		?name	      "mimwaffle_CTM"
    		?layer        CTM
    		?width        w
    		?length       l
    	)
    
    	R_tmp = rodCreateRect(
    		?layer        DUM
    		?width        (w+2*enc_CTM_DUM)
    		?length       (l+2*enc_CTM_DUM)
    	)
    
    	rodAlign(
    		?alignObj     R_tmp
    		?alignHandle  'centerCenter
    		?refObj       R_ref
    		?refHandle    'centerCenter
    	)
    	  
    	R_tmp = rodCreateRect(
    		?layer        MBOT
    		?width        (w+enc_CTM_MBOT*2)
    		?length       (l+enc_CTM_MBOT*2)
    		?termName	  "MINUS"
    	    ?termIOType	  "inputOutput"
    		?pin		  t
    		?pinLabel     t			
    	)
    
    	rodAlign(
    		?alignObj     R_tmp
    		?alignHandle  'centerCenter
    		?refObj       R_ref
    		?refHandle    'centerCenter
    	)
    	
    	; only draw the ABLB layer if enabled
    	if( ablb then
    		R_tmp = rodCreateRect(
    			?layer        ABLB
    			?width        (w+enc_ABLB_MBOT*2)
    			?length       (l+enc_ABLB_MBOT*2)					
    		)
    
    		rodAlign(
    			?alignObj     R_tmp
    			?alignHandle  'centerCenter
    			?refObj       R_ref
    			?refHandle    'centerCenter
    		)
    	)	
    	
    	; Checker to see if there's a need to waffle. Takes into account all the SBC18 Metal density rules
    		
    	cap_area = w*l
    	if( (cap_area <= 400.0) then
    		if( (w>=30 && l>=12)||(l>=30 && w>=12) then
    			waffle = 1
    		else
    			waffle = 0
    		) 
    	else
    		waffle = 1
    	)	
    	;warn("waffle pCell %d" waffle)
        
    	; you can safely ignore the code below this point if it helps
    		
    	;Check if you need to waffle
    	if( (waffle==0) then
    		s_via     = 1.0  ; For CTM area < 400 um^2
    		offset_var = offset_base
    		R_tmp = rodCreateRect(
    			?layer        MTOP
    			?width        w_MTOP
    			?length       l_MTOP
    			?termName	  "PLUS"
    	    	?termIOType	  "inputOutput"
    			?pin		  t
    			?pinLabel     t	
    			?subRectArray list(
    				list(
    				    	?layer                VIA
    			            ?length		           w_VIA
    		        	    ?width  		       w_VIA
    		        	    ?spaceX               s_via
    		        	    ?spaceY               s_via
    		        	    ?lowerLeftOffsetX     enc_VIA_MTOP
    		        	    ?lowerLeftOffsetY     enc_VIA_MTOP
    		        	    ?upperRightOffsetX   -enc_VIA_MTOP
    		        	    ?upperRightOffsetY   -enc_VIA_MTOP
    				)
    			);subRect
    		)
    		rodAlign(
    			?alignObj     R_tmp
    			?alignHandle  'lowerLeft
    			?refObj       R_ref
    			?refHandle    'lowerLeft
    			?xSep         offset_base
    			?ySep         offset_var
    			)
    	else
    	
    		; calculate the number of horizontal and vertical strips - this is now done in the callback
    		; Also calculate the horizontal and vertical spacing
    		;n_horiz_strips = floor((l_MTOP + hole_x_min)/(bar_w + hole_x_min))
    		sp_h = (float(l_MTOP) - bar_w*num_horiz_strips)/(num_horiz_strips - 1)
    		
    		;n_vertical_strips = floor((w_MTOP + hole_x_min)/(bar_w + hole_x_min))
    		sp_v = (float(w_MTOP) - bar_w*num_vertical_strips)/(num_vertical_strips - 1)
    		
    	
    		;Draw the horizontal bars
        	        ; calculate the number of horizontal vias
    		; including two vias in the horizontal spacing for now
    		x = bar_w - w_VIA + sp_v
    		via_pitch_x = (x-2*w_VIA)/3.0
    		;make sure we only use up to 2 significant digits
    		via_pitch_x = round(via_pitch_x*100)/100.0
    		;printf("X Pitch %f\n" via_pitch_x)
    		y = bar_w - w_VIA + sp_h
    		via_pitch_y = (y - 2*w_VIA)/3.0
    		via_pitch_y = round(via_pitch_y*100)/100.0
    		;printf("Y Pitch %f\n" via_pitch_y)
    		
    		; Determine the number of vias in the horizontal direction
    	        num_horiz_vias = num_vertical_strips + (num_vertical_strips-1)*2
    	        ; Some variables to help drawing	    
    	        bet_via_spacing = 0.5*(bar_w - w_VIA)
    		bar_offset = 0	    
    		
    		; start the loop to draw the horizontal strips 
    	        ; There's a nested loop within this to draw the vias
    	        ; within the via drawing the nested loop, first draw the vias at the intersection
    	        ; of the horizontal and vertical strips, then draw vias between them 
    	        ; to avoid replicating data, the intersection vias are only drawn once
    		
    		for( i 0 (num_horiz_strips-1)
    			; Draw the horizontal bars with the vias
    			; Make sure you only draw one pin on M3
    			R_tmp = rodCreateRect(
    					?layer  	MTOP
    					?length 	bar_w
    					?width  	w_MTOP	
    					?termName	  "PLUS"
    	    			?termIOType	  "inputOutput"
    					?pin		  t
    					?pinLabel     t						
    			)						
    			rodAlign(
    				?alignObj     R_tmp
    				?alignHandle  'lowerLeft
    				?refObj       R_ref
    				?refHandle    'lowerLeft
    				?ySep         bar_offset
    				)
    			for( j 0 (num_horiz_vias-1)
    				if( (remainder(j,3)==0) then
    					R_tmp1 = rodCreateRect(
    							?layer  VIA
    							?length w_VIA
    							?width 	w_VIA
    						)
    					rodAlign(
    							?alignObj     R_tmp1
    							?alignHandle  'lowerLeft
    							?refObj       R_tmp
    							?refHandle    'lowerLeft
    							?xSep         bet_via_spacing
    							?ySep		  0.5*(bar_w - w_VIA)
    						)
    					off_via_spacing = bet_via_spacing + w_VIA + via_pitch_x
    					bet_via_spacing = bet_via_spacing + bar_w + sp_v 													
    				else
    					R_tmp1 = rodCreateRect(
    							?layer  VIA
    							?length w_VIA
    							?width 	w_VIA
    						)
    					rodAlign(
    							?alignObj     R_tmp1
    							?alignHandle  'lowerLeft
    							?refObj       R_tmp
    							?refHandle    'lowerLeft
    							?xSep         off_via_spacing
    							?ySep		  0.5*(bar_w - w_VIA)
    						)
    					; draw the two between intersection vias at the spacing specified
    					off_via_spacing = off_via_spacing + w_VIA + via_pitch_x
    					
    				)					
    				
    			); end of via drawing inner loop
    			
    			bet_via_spacing = 0.5*(bar_w - w_VIA)
    			bar_offset = bar_offset + bar_w + sp_h
    				
    		); end of horiz strips for	
    		
    		; starting point is the location of the first via
    		; lowerLeft of the first via
    		bet_via_spacing = 0.5*(bar_w - w_VIA)
    		num_vertical_vias = num_horiz_strips + (num_horiz_strips-1)*2
    		bar_offset = 0
    		
    		
    		for( i 0 (num_vertical_strips-1)
    			;Draw the vertical bars with the vias
    			R_tmp = rodCreateRect(
    				?layer 		MTOP
    				?length 	l_MTOP
    				?width 		bar_w	
    				?termName	  "PLUS"
    	    		?termIOType	  "inputOutput"
    				?pin		  t
    				?pinLabel     t				
    			)
    			rodAlign(
    				?alignObj     R_tmp
    				?alignHandle  'lowerLeft
    				?refObj       R_ref
    				?refHandle    'lowerLeft
    				?xSep         bar_offset
    			)
    			for( j 0 (num_vertical_vias-1)
    				if( (remainder(j,3)==0) then
    					R_tmp1 = rodCreateRect(
    							?layer  VIA
    							?length w_VIA
    							?width 	w_VIA
    						)
    					rodAlign(
    							?alignObj     R_tmp1
    							?alignHandle  'lowerLeft
    							?refObj       R_tmp
    							?refHandle    'lowerLeft
    							?xSep         0.5*(bar_w - w_VIA)
    							?ySep		  bet_via_spacing
    						)
    					off_via_spacing = bet_via_spacing + w_VIA + via_pitch_y
    					bet_via_spacing = bet_via_spacing + bar_w + sp_h 													
    				else
    					R_tmp1 = rodCreateRect(
    							?layer  VIA
    							?length w_VIA
    							?width 	w_VIA
    						)
    					rodAlign(
    							?alignObj     R_tmp1
    							?alignHandle  'lowerLeft
    							?refObj       R_tmp
    							?refHandle    'lowerLeft
    							?xSep         0.5*(bar_w - w_VIA)
    							?ySep		  off_via_spacing
    						)
    					; draw the two between intersection vias at the spacing specified
    					off_via_spacing = off_via_spacing + w_VIA + via_pitch_y
    					
    				)					
    				
    			); end of via drawing inner loop
    			bet_via_spacing = 0.5*(bar_w - w_VIA)
    			bar_offset = bar_offset + bar_w + sp_v	
    		); End of vertical strip drawing loop
    	  			
    	); end of else if
    	
    	
    	
    ); end of let
    
    ); end of PCell definition
    
    
    
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 3 years ago in reply to Ynishant

    Could you also share the CDF for the cell? It's possible that's where the problem is (and it would be useful to know how the defaults and callbacks have been set up). If you don't have it as a file, if you could use Tools->CDF->Edit in the CIW, pick "Base", choose MIM_Pcell_Final and cmim1p35_2 as the cellView, and then use the "CDF Dump" button on the right side.

    I have the PCell running (I adjusted the layers for gpdk045) so should be able to fully test this.

    Thanks,

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Ynishant
    Ynishant over 3 years ago in reply to Andrew Beckett

    Sure, I've included it below. There are some lines that can be commented out without affecting functionality, especially the lines with "sbc18" or "jazzDisplayDeviceParams". Please let me know if the overall SKILL code can be improved in any way, or if there's a better way to do what I'm doing. 

    /****************************************************/
     LIBRARY = "MIM_Pcell_Final"
     CELL    = "cmim1p35_2"
    /****************************************************/
    
    
    let( ( libId cellId cdfId )
        unless( cellId = ddGetObj( LIBRARY CELL )
        	error( "Could not get cell %s." CELL )
        )
        when( cdfId = cdfGetBaseCellCDF( cellId )
            cdfDeleteCDF( cdfId )
        )
        cdfId  = cdfCreateBaseCellCDF( cellId )
    
        ;;; Parameters
        cdfCreateParam( cdfId
            ?name           "macro"
            ?prompt         "Subcircuit Filename"
            ?defValue       "c2t_mim1p35_cu"
            ?type           "string"
            ?display        "jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "m"
            ?prompt         "Multiplier"
            ?defValue       "1"
            ?type           "string"
            ?callback       "mim_cb( 'm )"
            ?storeDefault   "yes"   
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"     
        )
        cdfCreateParam( cdfId
            ?name           "caprows"
            ?prompt         "Rows"
            ?defValue       "1"
            ?type           "string"
    		;?display        "sbc18_capDisplay( 'caprows ) && jazzDisplayDevParams(\"cmim1p35_2\")"
           	?display        "nil"
            ?editable       "t"
    		;?callback       "sbc18_capCB( 'caprows )"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "capcols"
            ?prompt         "Columns"
            ?defValue       "1"
            ?type           "string"
    		;?display        "sbc18_capDisplay( 'capcols ) && jazzDisplayDevParams(\"cmim1p35_2\")"
           	?display        "nil"
            ?editable       "t"
            ;?callback       "sbc18_capCB( 'capcols )"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "Calculate"
            ?prompt         "Calculate"
            ?defValue       "C"
            ?choices        '("C" "L" "W" "WL")
            ?type           "radio"
            ?editable       "nil"
    		?storeDefault   "yes"        
        )
        cdfCreateParam( cdfId
            ?name           "c"
            ?prompt         "Capacitance"
            ?defValue       "309.8f"
            ?type           "string"
            ?callback       "mim_cb( 'c )"
            ?editable       "nil"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "w"
            ?prompt         "Width"
            ?defValue       "15u"
            ?type           "string"
            ?callback       "mim_cb( 'Width )"
    		?storeDefault   "yes"
    		?parseAsNumber  "yes"
            ?parseAsCEL     "yes"        
        )
        cdfCreateParam( cdfId
            ?name           "l"
            ?prompt         "Length"
            ?defValue       "15u"
            ?type           "string"
            ?callback       "mim_cb( 'Length )"
    		?storeDefault   "yes" 
    		?parseAsNumber  "yes"
            ?parseAsCEL     "yes"       
        )
        cdfCreateParam( cdfId
            ?name           "aspect_ratio"
            ?prompt         "Aspect Ratio(w/l)"
            ?defValue       "1"
            ?type           "string"
            ?editable       "nil"
    		?storeDefault   "yes"  
    		?parseAsNumber  "yes"
            ?parseAsCEL     "yes"      
        )
        cdfCreateParam( cdfId
            ?name           "dx"
            ?prompt         "dx"
            ?defValue       "-120n"
            ?type           "string"
            ?editable       "nil"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "ablb"
            ?prompt         "Enable ABLB"
            ?defValue       t
            ?type           "boolean"
            ?editable       "t"
    		?storeDefault   "yes"        
        )
        cdfCreateParam( cdfId
            ?name           "cmm"
            ?prompt         "Nominal Unit Area Capacitance"
            ?defValue       "1.35m"
            ?type           "string"
            ?editable       "nil"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "fringe"
            ?prompt         "Nominal Unit Fringe Capacitance"
            ?defValue       "150p"
            ?type           "string"
            ?editable       "nil"
    	    ?storeDefault   "yes"
    	    ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"        
        )
        cdfCreateParam( cdfId
            ?name           "m3_density"
            ?prompt         "Density of the M3 layer on the Cap(%)"
            ?defValue       "73"
            ?type           "string"
            ?editable       "nil"       
        )
        cdfCreateParam( cdfId
            ?name           "n_horiz_strips"
            ?prompt         "Number of horizontal strips"
            ?defValue       "0"
            ?type           "string"
            ?storeDefault   "yes"  
            ?editable       "nil"      
        )
        cdfCreateParam( cdfId
            ?name           "n_vertical_strips"
            ?prompt         "Number of vertical strips"
            ?defValue       "0"
            ?type           "string"
            ?storeDefault   "yes"  
            ?editable       "nil"      
        )
        cdfCreateParam( cdfId
            ?name           "rem_h_strip"
            ?prompt         "Number of Horizontal Strips To Remove(Limit 2)"
            ?defValue       "0"
            ?type           "string"
            ?storeDefault   "yes"        
        )    
        cdfCreateParam( cdfId
            ?name           "showSimParams"
            ?prompt         "Show Sim Parameters"
            ?type           "boolean"
            ?display        "sbc18_capDisplay('showSimParams)"
        )
        cdfCreateParam( cdfId
            ?name           "cmima_max"
            ?prompt         "Max Unit Area Capacitance"
            ?defValue       "1.55m"
            ?type           "string"
            ?display        "sbc18_capDisplay('cmima_max) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "cmimp_max"
            ?prompt         "Max Unit Fringe Capacitance"
            ?defValue       "225p"
            ?type           "string"
            ?display        "sbc18_capDisplay('cmimp_max) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "coxa_nom"
            ?prompt         "coxa_nom"
            ?defValue       "15.1u"
            ?type           "string"
            ?display        "sbc18_capDisplay('coxa_nom) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "coxa_max"
            ?prompt         "coxa_max"
            ?defValue       "17.5u"
            ?type           "string"
            ?display        "sbc18_capDisplay('coxa_max) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "coxp_nom"
            ?prompt         "coxp_nom"
            ?defValue       "37.4p"
            ?type           "string"
            ?display        "sbc18_capDisplay('coxp_nom) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "coxp_max"
            ?prompt         "coxp_max"
            ?defValue       "38.7p"
            ?type           "string"
            ?display        "sbc18_capDisplay('coxp_max) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "rshbp_nom"
            ?prompt         "rshbp_nom"
            ?defValue       "66m"
            ?type           "string"
            ?display        "sbc18_capDisplay('rshbp_nom) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "rshbp_max"
            ?prompt         "rshbp_max"
            ?defValue       "86m"
            ?type           "string"
            ?display        "sbc18_capDisplay('rshbp_max) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "rshtp_nom"
            ?prompt         "rshtp_nom"
            ?defValue       "5.4m"
            ?type           "string"
            ?display        "sbc18_capDisplay('rshtp_nom) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "rshtp_max"
            ?prompt         "rshtp_max"
            ?defValue       "7m"
            ?type           "string"
            ?display        "sbc18_capDisplay('rshtp_max) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "tc"
            ?prompt         "tc"
            ?defValue       "20u"
            ?type           "string"
            ?display        "sbc18_capDisplay('tc) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "tbp"
            ?prompt         "tbp"
            ?defValue       "620n"
            ?type           "string"
            ?display        "sbc18_capDisplay('tbp) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "ttp"
            ?prompt         "ttp"
            ?defValue       "3.3u"
            ?type           "string"
            ?display        "sbc18_capDisplay('ttp) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "rvia"
            ?prompt         "rvia"
            ?defValue       "3.5"
            ?type           "string"
            ?display        "sbc18_capDisplay('rvia) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        cdfCreateParam( cdfId
            ?name           "wvia"
            ?prompt         "wvia"
            ?defValue       "380n"
            ?type           "string"
            ?display        "sbc18_capDisplay('wvia) && jazzDisplayDevParams(\"cmim1p35_2\")"
            ?editable       "nil"
            ?storeDefault  "yes"
            ?parseAsNumber  "yes"
            ?parseAsCEL     "yes"
        )
        
        ;;; Simulator Information
        cdfId->simInfo = list( nil )
        cdfId->simInfo->ads = '( nil
            namePrefix        ""
            netlistProcedure  IdfCompPrim
            otherParameters   nil
            instParameters    (w l caprows capcols _M cmima_nom cmima_max cmimp_nom cmimp_max coxa_nom coxa_max coxp_nom coxp_max rshtp_nom rshtp_max rshbp_nom rshbp_max tc tbp ttp rvia wvia)
            propMapping       (nil _M m)
            typeMapping       nil
            uselib            nil
            termOrder         (PLUS MINUS)
            termMapping       (nil PLUS ":P1" MINUS ":P2")
            componentName     "c2t_mim2_cu"
        )
        cdfId->simInfo->ams = '( nil
            componentName     "c2t_mim2_cu"
        )
        cdfId->simInfo->auCdl = '( nil
            propMapping       (nil C cvalCdl M simM L l W w sim_tc tc dspfsim macro)
            termOrder         (PLUS MINUS)
            netlistProcedure  jazzCdlSubcktCall
            instParameters    (C M L W dspfsim macro cmima_nom cmima_max cmimp_nom cmimp_max coxa_nom coxa_max coxp_nom coxp_max rshtp_nom rshtp_max rshbp_nom rshbp_max sim_tc tbp ttp rvia wvia)
            namePrefix        "X"
            modelName         "cmim1p35_2"
        )
        cdfId->simInfo->auLvs = '( nil
            propMapping       nil
            netlistProcedure  ansLvsCompPrim
            instParameters    (m capcols caprows c)
            parameters        (C)
            permuteRule       "(p PLUS MINUS)"
            namePrefix        "C"
            termOrder         (PLUS MINUS)
            deviceTerminals   "PLUS MINUS"
            componentName     "cmim1p35_2"
        )
        cdfId->simInfo->eldoD = '( nil
            netlistProcedure  nil
            propMapping       nil
            instParameters    (w l caprows capcols m cmima_nom cmima_max cmimp_nom cmimp_max coxa_nom coxa_max coxp_nom coxp_max rshtp_nom rshtp_max rshbp_nom rshbp_max tc tbp ttp rvia wvia)
            namePrefix        "X"
            current           port
            noPortDelimiter   t
            dcSens            t
            acSens            t
            termOrder         (PLUS MINUS)
            termMapping       (nil PLUS "(FUNCTION mappedRoot(\"^l1\"))" MINUS "(FUNCTION minus(mappedRoot(\"^l2\")))")
            componentName     "c2t_mim2_cu"
        )
        cdfId->simInfo->hspiceD = '( nil
            netlistProcedure  nil
            propMapping       nil
            instParameters    (w l caprows capcols m cmima_nom cmima_max cmimp_nom cmimp_max coxa_nom coxa_max coxp_nom coxp_max rshtp_nom rshtp_max rshbp_nom rshbp_max tc tbp ttp rvia wvia)
            namePrefix        "X"
            current           port
            noPortDelimiter   t
            dcSens            t
            acSens            t
            termOrder         (PLUS MINUS)
            termMapping       (nil PLUS "(FUNCTION mappedRoot(\"^l1\"))" MINUS "(FUNCTION minus(mappedRoot(\"^l2\")))")
            componentName     "c2t_mim2_cu"
        )
        cdfId->simInfo->spectre = '( nil
            propMapping       (nil model macro)
            instParameters    (w l caprows capcols m cmima_nom cmima_max cmimp_nom cmimp_max coxa_nom coxa_max coxp_nom coxp_max rshtp_nom rshtp_max rshbp_nom rshbp_max tc tbp ttp rvia wvia)
            netlistProcedure  nil
            termOrder         (PLUS MINUS)
            termMapping       (nil PLUS \:1 MINUS \:2)
            opParamExprList   (("cval" "OP(mappedRoot(\".c3\") \"cap\")") ("cbot" "OP(mappedRoot(\".c1\") \"cap\")+OP(mappedRoot(\".c2\") \"cap\")"))
        )
    
        
        
    
        ;;; Properties
        cdfId->formInitProc            = "mim_m2cs_init"
        cdfId->doneProc                = ""
        cdfId->buttonFieldWidth        = 340
        cdfId->fieldHeight             = 35
        cdfId->fieldWidth              = 350
        cdfId->promptWidth             = 175
        cdfId->paramLabelSet           = "w l c m caprows capcols"
        cdfId->opPointLabelSet         = "cval cbot cfox"
        cdfId->modelLabelSet           = ""
        cdfId->paramDisplayMode        = "parameter"
        cdfId->paramEvaluate           = "nil nil nil nil t"
        cdfId->paramSimType            = "DC"
        cdfId->termSimType             = "DC"
        cdfId->instDisplayMode         = "instName"
        cdfId->instNameType            = "schematic"
        
        cdfSaveCDF( cdfId )
    )
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 3 years ago in reply to Ynishant

    OK, this ended up being down to a couple of things:

    1. A difference in the condition in determining whether it was in "waffle mode" or not between the callback and the PCell code
    2. Floating point rounding errors - caused by a difference in using cdfParseFloatString (callbacks) and evalstring (PCell). Neither approach is really safe, as doing equality checks or >= checks is always dangerous with floating point numbers as I'll show in a moment.

    First of all, the difference. The PCell code looks like this:

    	cap_area = w*l
    	if( (cap_area <= 400.0) then
    		if( (w>=30 && l>=12)||(l>=30 && w>=12) then
    			waffle = 1
    		else
    			waffle = 0
    		) 
    	else
    		waffle = 1
    	)	
    	;warn("waffle pCell %d" waffle)

    and the CDF callback like this:

        if(cap_area <= 400.0
            then
                if(((w_n > 30) && (l_n > 12)) || ((l_n > 30) && (w_n > 12))
                    then
                        waffle = 1
                    else
                        waffle = 0
                   )
            else
                waffle = 1
           )
     

    Notice that the red lines are different - the PCell code is using >= whereas the callback code is using >. However, that is not enough to fix it.. If you add some print statements (I tend to use fprintf to print to stderr as that then prints in the CIW for PCells, rather than adding a marker onto the PCell) - I added this to the PCell code (where y ou had the warn("waffle pCell"... line above):

    	fprintf(stderr "PC: waffle %d w %.18g l %.18g\n" waffle w l)
    

    and this to the callback code (just above the if statement I show above):

        fprintf(stderr "CB: cap_area %.18g w %.18g l %.18g\n" cap_area w_n l_n)
    

    Running this with w=30u and l=12u you see this in the CIW (note the difference in waffle value between callback and the pcell too):

    CB: cap_area 359.999999999999943 w 29.9999999999999964 l 12
    *WARNING* Waffle Status 0
    *WARNING* Initial Values: w=3e-05 l=1.2e-05 c=6.13657e-13 ratio=2
    PC: waffle 1 w 30 l 12

    Looking closely, it's because there are small differences between cdfParseFloatString and evalstring. You might think "ah, I'll just use evalstring in both places", and that does fix it in this case, but I'd also suggest that there's no guarantee that other numbers might similarly end up with small rounding errors when multiplied by the 1e6 scale). Also, I dislike using evalstring because I always think of the case "what if the user entered exit() in the field?" (your PCell might then cause Virtuoso to quit!).

    Instead, it's better to do the comparison with some epsilon (or error) value which allows a safety margin for tiny rounding errors. A reasonable value for that might be around half a database unit. So maybe you could instead change the conditions to this for the PCel (note that the epsilon is either added or subtracted depending on the direction of the comparisonl:

    	epsilon=0.0005
    	if( (cap_area <= 400.0+epsilon) then
    		if( (w>=30-epsilon && l>=12-epsilon)||(l>=30-epsilon && w>=12-epsilon) then
    			waffle = 1
    		else
    			waffle = 0
    		) 
    	else
    		waffle = 1
    	)

    and this for the callback:

        epsilon = 0.0005
        fprintf(stderr "CB: cap_area %.18g w %.18g l %.18g\n" cap_area w_n l_n)
        if(cap_area <= 400.0+epsilon
            then
                ;if(((w_n > 30) && (l_n > 12)) || ((l_n > 30) && (w_n > 12))
                if(((w_n >= 30-epsilon) && (l_n >= 12-epsilon)) || ((l_n >= 30-epsilon) && (w_n >= 12-epsilon))
                    then
                        waffle = 1
                    else
                        waffle = 0
                   )
            else
                waffle = 1
           )
    
    
    

    With this, the resulting info with w=30u and l=12u:

    CB: cap_area 359.999999999999943 w 29.9999999999999964 l 12
    *WARNING* Waffle Status 1
    *WARNING* Initial Values: w=3e-05 l=1.2e-05 c=4.91743e-13 ratio=2.5
    PC: waffle 1 w 30 l 12

    See that the waffle status is now consistent. I didn't fully check the behaviour of the PCell because I wasn't entirely sure what you were expecting it to do, but I think that's the part you had the concerns about. Be aware that floating point rounding errors happen in any programming language that uses IEEE floating point representation for numbers (so it affects C, Python, SKILL and many others) - you just have to be aware that a single bit error in the 53 bit mantissa can cause all sorts of problems and any equality check is dangerous because of tiny differences due to how you do the maths. A simple example I always like to give is that 0.1 in binary is a recurring fraction like 1/3 is in decimal - so you can easily imagine how you lose precision such as you do by representing 1/3 as 0.333 - for example, if you did (in pseudo code)

    third=0.333
    if third*3==1 then...

    well, surprise, surprise - it doesn't equal 1 - the same thing is happening here but with a long binary mantissa.

    I haven't reviewed all the code to give advice (to be honest, I don't have time - explaining this took long enough having gradually collected all the data to reproduce it), but hopefully the above explanation will give you enough to review your code for other potential similar problems.

    Regards,

    Andrew

    • Cancel
    • Vote Up +1 Vote Down
    • Cancel
  • Ynishant
    Ynishant over 3 years ago in reply to Andrew Beckett

    Brilliant! Yes, this actually makes sense to me and the reason why I changed the ">=" to ">" in the waffle callback check was precisely because that single change made the code work for the second case that was failing before - when the W = 30 um and L = 13 um. That should've nudged me to look at the difference between the evalstring and cdfParseFloatString (and I suspected there might be a difference but I didn't explore that). That should've also nudged me to look at any floating math issues! While debugging, I used the "%f" qualifier to print the W and L values so I didn't notice the differences in the significant digits. Lesson learned...

    I think I'm all set and thank you for all your help! 

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel

Community Guidelines

The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.

© 2025 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information