• 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. Freezing Pcells for tapeout with external code in libInit...

Stats

  • Locked Locked
  • Replies 2
  • Subscribers 144
  • Views 14067
  • 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

Freezing Pcells for tapeout with external code in libInit.il files

patschouly
patschouly over 5 years ago

In our team we make a hierarchical copy of our individual blocks for the final library in a tapeout. I'm using some pcells that rely on code in the libInit files. However, the hierarchical copy copies only the cell, obviously not the needed code in the libInit file. Is there a way to automatically flatten (or something else) these pcells to have a truly standalone library (without other team members needing access to the original pcell library with the respective libInit files)? This is not necessarily a question about SKILL, if there is something implemented in virtuoso I'm happy to use that.

Kind regards,

Patrick

  • Cancel
  • Sheppie
    Sheppie over 5 years ago

    Hi Patrick,

    If I understand you correctly, you want to flatten instances from a certain library in the entire design.

    Some code I wrote at least 10 years ago (with limited SKILL experience, so it could be written more efficiently) does just that: it looks for instances (pcells) from a specific library in cells in a library and flattens them. In stead of it being just floating polygons, all polygons from the pcells are grouped, and the parameter values of the original pcell are attached to the group for future reference.

    I needed to do this since a colleague of mine wrote some pyCells (Python P-Cells) and the Python version he used was not supported by Virtuoso after an update. See the attached file, and load it in CIW:

    Fullscreen 3288.flattenPycells.il.txt Download
    ;;; -------------------------------------------------------------------------------------------------------
    ;;; Change history:
    ;;;
    ;;; Initial version, containing:
    ;;; - The GUI
    ;;; - The actual code to find the instances
    ;;; - Code to create a group with only one pyCell, store pyCell properties to the group
    ;;;   and flatten the content of the group
    ;;; - Output log code
    ;;; -------------------------------------------------------------------------------------------------------
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;
    ;;; _WARNING_WARNING_WARNING_WARNING_WARNING_
    ;;;
    ;;; IF YOU OPEN THIS FILE IN NEDIT, THE TABs WILL NOT BE THE SAME AS IN THE SKILL DEVELOPMENT ENVIRONMENT EDITOR (INSIDE VIRTUOSO)
    ;;; THIS CODE HAS BEEN WRITTEN IN THE BUILD-IN EDITOR OF VIRTUOSO. TO GET THERE: CIW -> TOOLS -> SKILL DEVELOPMENT ENVIRONMENT
    ;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;; This is the procedure with which all starts...
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    procedure( flattenPycells()
    	let( ( ( theLibList nil ) )
    
    		theLibList = FPCDefineLibList()
    
    		FPCBuildGui( theLibList )						;;; Load GUI and continue
    
    	) ;;; end let
    ) ;;; end procedure
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; Building the GUI form...
    procedure( FPCBuildGui( theLibList "l" )
    	let( ()
    		FPCSourceLibrary = hiCreateCyclicField(
    			?name			'FPCSourceLibrary
    			?choices		theLibList
    			?prompt		"Source library:"
    			?callback		"FPCSourceLibSelectedCB()"
    		)
    
    		FPCSourceLibraryLabel1 = hiCreateLabel( 
    			?name 			 'FPCSourceLibraryLabel1
    			?labelText 		"This is the library with the source of the pycells."
    			?justification 	'left
    			?enabled		t
    		)
    
    		FPCOutputFileName = hiCreateStringField(
    			?name			'FPCOutputFileName
    			?prompt		"Log output file name:"
    			?value			"flattened_pycells.txt"
    			?defValue		"flattened_pycells.txt"
    			?callback		"nil"
    			?editable		t
    			?enabled		t
    		)
    
    		FPCOutputFileNameLabel1 = hiCreateLabel( 
    			?name 			 'FPCOutputFileNameLabel1
    			?labelText 		"Log-file will be opened after run completes."
    			?justification 	'left
    			?enabled		t
    		)
    
    		FPCLibsToBrowse = hiCreateListBoxField(
    			?name			'FPCLibsToBrowse	
    			?choices		theLibList
    			?callback		"FPCLibsToBrowseSelectedCB()"
    			?prompt		"Libraries to browse:"
    			?multipleSelect	t
    			?enabled		nil
    		)
    		
    		FPCCellsToBrowse = hiCreateListBoxField(
    			?name			'FPCCellsToBrowse	
    			?choices		list( "Select libraries to browse..." )
    			?callback		"FPCCellsToBrowseSelectedCB()"
    			?prompt		"Cells to browse:"
    			?multipleSelect	t
    			?enabled		nil
    		)
    		
    		FPCSelectAllCells = hiCreateButton(
    			?name			'FPCSelectAllCells
    			?buttonText		"Select all"
    			?callback		"FPCSelectAllCellsClickedCB()"
    			?enabled		nil
    			)
    
    		FPCViewsToBrowse = hiCreateListBoxField(
    			?name			'FPCViewsToBrowse	
    			?choices		list( "Select cells to browse..." )
    			?changeCB		"FPCViewsToBrowseSelectedCB()"
    			?prompt		"Views to browse:"
    			?multipleSelect	t
    			?enabled		nil
    		)
    		
    		FPCSelectAllViews = hiCreateButton(
    			?name			'FPCSelectAllViews
    			?buttonText		"Select all"
    			?callback		"FPCSelectAllViewsClickedCB()"
    			?enabled		nil
    			)
    
    		FPCGroupNamePrefix = hiCreateStringField(
    			?name			'FPCGroupNamePrefix
    			?prompt		"Groupname prefix:"
    			?value			"flat_pycell_"
    			?defValue		"flat_pycell_"
    			?callback		"nil"
    			?editable		nil
    			?enabled		nil
    		)
    
    		FPCDryRunOnly = hiCreateToggleField(
    			?name 			'FPCDryRunOnly
    			?choices		list( list( 'dryRun "No changes to database, log-file only." ) )
    			?prompt		"Dry-run only:"
    			?value 		'( t )
    			?defValue 		'( t )
    			?enabled		nil
    			)
    
    		FPCVerboseOutput = hiCreateToggleField(
    			?name 			'FPCVerboseOutput
    			?choices		list( list( 'verbose "Also feedback in CIW if enabled" ) )
    			?prompt		"Verbose output:"
    			?value 		'( nil )
    			?defValue 		'( nil )
    			?enabled		nil
    			)
    
    		;;;;;;;;;;;;;;;;;;;;;;
    		;;; Building the form...
    		hiCreateAppForm(
    			?name 			'FPCGuiForm
    			?formTitle		"Flatten pyCells..."
    			?callback		"FPCFlattenPyCellsCB()"
    			?dontBlock		t
    			?fields		list( 
    							list( FPCSourceLibrary			10:10		200:30		150 )
    							list( FPCSourceLibraryLabel1		150:30		290:30		150 )
    							list( FPCOutputFileName			910:10		440:30		150 )
    							list( FPCOutputFileNameLabel1		1055:40	295:20		150 )
    							
    							list( FPCLibsToBrowse			10:90		440:200	150 )
    							list( FPCCellsToBrowse			460:90		440:200	150 )
    							list( FPCSelectAllCells			460:110	130:30		150 )
    							list( FPCViewsToBrowse			910:90		440:200	150 )
    							list( FPCSelectAllViews			910:110	130:30		150 )
    							
    							list( FPCGroupNamePrefix			10:290		440:30		150 )
    							list( FPCDryRunOnly				460:293	440:30		150 )
    							list( FPCVerboseOutput			910:293	440:30		150 )
    						) ;;; end list ?fields
    			?buttonLayout		list(
    							'OKCancelApply
    						) ;;; end list ?buttonLayout
    			?buttonDisabled	list( 'OK 'Apply 'Help )
    			?unmapAfterCB		t
    			?initialSize		1400:600
    		) ;;; end hiCreateAppForm
    		;;;;;;;;;;;;;;;;;;;;;;
    
    		;;;;;;;;;;;;;;;;;;;;;;
    		;;; Displaying the form
    		hiDisplayForm( FPCGuiForm 125:125 )
    		;;;;;;;;;;;;;;;;;;;;;;
    		
    	) ;;; end let
    ) ;;; end procedure FPBuildGui
    ;;;;;;;;;;;;;;;;;;;;;;
    		
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; After the source library (the library with the actual pycells) has been selected, this procedure is called.
    procedure( FPCSourceLibSelectedCB()
    	let( ()
    		when( FPCGuiForm~>FPCSourceLibrary~>value
    			FPCGuiForm~>FPCLibsToBrowse~>enabled = t
    		) ;;; end when
    	) ;;; end let
    ) ;;; end procedure FPCSourceLibrarySelected
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; After the libraries to browse have been selected, this procedure is called.
    procedure( FPCLibsToBrowseSelectedCB()
    	let( ()
    		when( FPCGuiForm~>FPCLibsToBrowse~>value
    			FPCGuiForm~>FPCCellsToBrowse~>choices = FCPDefineCellList( FPCGuiForm~>FPCLibsToBrowse~>value )
    			FPCGuiForm~>FPCCellsToBrowse~>enabled = t
    			FPCGuiForm~>FPCSelectAllCells~>enabled = t
    		) ;;; end when
    	) ;;; end let
    ) ;;; end procedure FPCLibsToBrowseSelectedCB
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; After the clles to browse have been selected, this procedure is called.
    procedure( FPCSelectAllCellsClickedCB()
    	let( ()
    		FPCGuiForm~>FPCCellsToBrowse~>value = FPCGuiForm~>FPCCellsToBrowse~>choices
    	) ;;; end let
    ) ;;; end procedure FPCCellsToBrowseSelectedCB
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; After the clles to browse have been selected, this procedure is called.
    procedure( FPCCellsToBrowseSelectedCB()
    	let( ( ( viewTypeList nil ) ( viewNameList nil ) )
    	
    		viewTypeList = list( "layout" "maskLayout" "maskLayoutGXL" "maskLayoutXL" )
    		
    		when( FPCGuiForm~>FPCCellsToBrowse~>value
    			viewNameList = FPCDefineViewList( FPCGuiForm~>FPCLibsToBrowse~>value FPCGuiForm~>FPCCellsToBrowse~>value viewTypeList )
    			if( !viewNameList
    			then
    				viewNameList = list( "No views in library/libraries..." )
    				FPCGuiForm~>FPCViewsToBrowse~>enabled = nil
    				FPCGuiForm~>FPCSelectAllViews~>enabled = t
    			else
    				FPCGuiForm~>FPCViewsToBrowse~>enabled = t
    				FPCGuiForm~>FPCSelectAllViews~>enabled = t
    			) ;;; end if
    		
    			FPCGuiForm~>FPCViewsToBrowse~>choices = viewNameList
    
    		) ;;; end when
    	) ;;; end let
    ) ;;; end procedure FPCCellsToBrowseSelectedCB
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; After the clles to browse have been selected, this procedure is called.
    procedure( FPCSelectAllViewsClickedCB()
    	let( ()
    		FPCGuiForm~>FPCViewsToBrowse~>value = FPCGuiForm~>FPCViewsToBrowse~>choices
    	) ;;; end let
    ) ;;; end procedure FPCCellsToBrowseSelectedCB
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; After the views to browse have been selected, this procedure is called.
    procedure( FPCViewsToBrowseSelectedCB()
    	let( ()
    		FPCGuiForm~>FPCGroupNamePrefix~>enabled = t
    		FPCGuiForm~>FPCGroupNamePrefix~>editable = t
    		FPCGuiForm~>FPCDryRunOnly~>enabled = t
    		FPCGuiForm~>FPCVerboseOutput~>enabled = t
    		hiSetFormButtonEnabled( FPCGuiForm 'OK t )
    		hiSetFormButtonEnabled( FPCGuiForm 'Apply t )
    	) ;;; end let
    ) ;;; end procedure FPCCellsToBrowseSelectedCB
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; Creating a list of all libraries connected in the library manager.
    procedure( FPCDefineLibList()
    	let( ( ( theLibList nil ) ( tempLibList nil ) )
    
    		tempLibList = ddGetLibList()
    
    		foreach( libDbId tempLibList
    			theLibList = append( theLibList list( libDbId~>name ) )
    		) ;;; end foreach
    
    		theLibList = ( sort theLibList nil )
    
    	) ;;; end let
    ) ;;; end procedure FPCDefineLibList
    ;;;;;;;;;;;;;;;;;;;;;;
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; List all cells in the selected reference library...
    procedure( FCPDefineCellList( libList "l" )
    	let( ( ( cellNameList nil ) )
    
    		foreach( lib libList
    			foreach( cell ddGetObj( lib )~>cells
    				if( member( cell~>name cellNameList )
    				then
    					warn( "- Cells with same name in multiple libraries, first one used. Duplicate: %s - %s\n" lib cell~>name )
    					cellNameList = cellNameList
    				else
    					cellNameList = append( cellNameList list( cell~>name ) )
    				) ;;; end if
    			) ;;; end foreach cell
    		) ;;; end foreach lib
    
    		cellNameList = ( sort cellNameList nil )
    		
    	) ;;; end let
    ) ;;; end procedure FCPDefineCellList
    ;;;;;;;;;;;;;;;;;;;;;;
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; Creating a list of all views of all selected cells in the selected libraries to browse.
    procedure( FPCDefineViewList( libList cellList viewTypeList "lll" )
    	let( ( ( viewList nil ) ( viewNameList nil )
    		( viewType nil )
    		( cellsToProcess 0 ) ( cellCount 1 ) )
    		
    		;;; Get the number of cells to process, needed to set the totalSteps value of the progressbox...
    		cellsToProcess = length( cellList )
    		
    		;;; Create and display the progressbox, unless there are no views...
    		unless( zerop( cellsToProcess )
    			hiDisplayProgressBox(
    				?name			'FPCProgressBoxViewnameList
    				?banner		"Processing..."
    				?text			"Processing cells in selected libraries, please wait..."
    				?totalSteps		cellsToProcess
    				?autoClose		t
    			)
    		) ;;; end unless
    		
    		hiSetProgressButtonText( FPCProgressBoxViewnameList "Close" )
    		
    		foreach( lib libList
    			foreach( cell setof( x ddGetObj( lib )~>cells~>name member( x cellList ) )
    				viewList = ddGetObj( lib cell )~>views~>name
    				foreach( view viewList
    					viewType = dbGetq( FPCOpenCellViewByType( lib cell view nil "r" ) cellViewType )
    					when( member( viewType viewTypeList )
    						if( member( view viewNameList )
    						then
    							viewNameList = viewNameList
    						else
    							viewNameList = append( viewNameList list( view ) )
    						) ;;; end if
    					) ;;; end when			
    				) ;;; end foreach
    				
    				;;; Update the value of the progressbox, only when there is a progressbox...
    				when( FPCProgressBoxViewnameList
    					hiSetProgress( FPCProgressBoxViewnameList cellCount )
    					cellCount++
    				) ;;; end unless
    					
    			) ;;; end foreach cell
    		) ;;; end foreach lib
    
    		;;; Make sure that the progressbox reaches 100%...
    		when( FPCProgressBoxViewnameList
    			hiSetProgress( FPCProgressBoxViewnameList cellsToProcess )
    		) ;;; end unless
    					
    		viewNameList = ( sort viewNameList nil )
    
    	) ;;; end let
    ) ;;; end procedure FPCDefineViewList
    ;;;;;;;;;;;;;;;;;;;;;;
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; Creating a list of all views of all selected cells in the selected libraries to browse.
    procedure( FPCFlattenPyCellsCB()
    	let( ( ( sourceLib nil ) ( libList nil ) ( cellList nil ) ( viewList nil ) ( dryRunOnly nil ) ( verbose nil ) ( prefix nil )
    		( cellView nil ) ( instanceName nil )
    		( cellViewShapeList nil ) ( newCellViewShapeList nil )
    		( viewsToProcess 0 ) ( viewCount 1 ) ( detailedInfoList nil ) ( detailedInfo nil )
    		( pyCellDefaultList nil )
    		( parameterName nil ) ( parameterType nil ) ( parameterValue nil )
    		( groupName nil ) ( groupID nil )
    		( openViewMode "r" ) ( dryRunPrintString "DRYRUN: "  )
    		( myPort nil ) ( outputFileName "" ) ( cellViewCount 0 ) ( totalInstanceCount 0 ) ( instanceCount 0 ) ( valid nil ) )
    		
    		pyCellDefaultList = list(
    			list( "mosType" "string" "nmos" )
    			list( "sourceLayer" "string" "M1" )
    			list( "drainLayer" "string" "M1" )
    			list( "wf" "float" 0.12 )
    			list( "lf" "float" 0.04 )
    			list( "sourcext" "float" 0.04 )
    			list( "drainext" "float" 0.04 )
    			list( "bulkContact" 'boolean nil )
    			list( "ruleset" "string" "default" )
    		) ;;; end list pyCellDefaults
    		
    		sourceLib = FPCGuiForm~>FPCSourceLibrary~>value
    		libList = FPCGuiForm~>FPCLibsToBrowse~>value
    		cellList = FPCGuiForm~>FPCCellsToBrowse~>value
    		viewList = FPCGuiForm~>FPCViewsToBrowse~>value
    		dryRunOnly = car( FPCGuiForm~>FPCDryRunOnly~>value )
    		verbose = car( FPCGuiForm~>FPCVerboseOutput~>value )
    		prefix = FPCGuiForm~>FPCGroupNamePrefix~>value
    		outputFileName = FPCGuiForm~>FPCOutputFileName~>value
    		
    		;;; Depending on the dryRunOnly option, change the open mode (read only or append?)
    		if( dryRunOnly
    		then
    			openViewMode = "r"
    			dryRunPrintString = "DRYRUN: "
    		else
    			openViewMode = "a"
    			dryRunPrintString = ""
    		) ;;; end if dryRunOnly
    		
    		;;; Calculate the number of views to process, needed to set the totalSteps value of the progressbox...
    		foreach( lib libList
    			foreach( cell setof( x ddGetObj( lib )~>cells~>name member( x cellList ) )
    				foreach( view setof( y ddGetObj( lib cell )~>views~>name member( y viewList ) )
    					viewsToProcess++
    				) ;;; end foreach view
    			) ;;; end foreach cell
    		) ;;; end foreach lib
    		
    		;;; Create and display the progressbox...
    		unless( zerop( viewsToProcess )
    			hiDisplayProgressBox(
    				?name			'FPCProgressBoxBatchJob
    				?banner		"Processing..."
    				?text			"Processing cells in selected libraries, please wait..."
    				?totalSteps		viewsToProcess
    				?autoClose		t
    			)
    		) ;;; end unless
    		
    		hiSetProgressButtonText( FPCProgressBoxBatchJob "Close" )
    		
    		;;; Open the port to the output file...
    		myPort = outfile( outputFileName "w" )
    		
    		;;; Create the header of the file
    		fprintf( myPort "Output file of the flatten pycells script.\n" )
    		fprintf( myPort "--------------------- USER SETTINGS -------------------\n" )
    		fprintf( myPort "Settings made:\n" )
    		fprintf( myPort "Source library: %L\n" sourceLib )
    		fprintf( myPort "Search librar(y/ies): %L\n" libList )
    		fprintf( myPort "Search cell(s): %L\n" cellList )
    		fprintf( myPort "Search view(s): %L\n" viewList )
    		fprintf( myPort "Output file name: %L\n" outputFileName )
    		fprintf( myPort "Dry-run only: %L\n" dryRunOnly )
    		fprintf( myPort "Verbose output: %L\n" verbose )
    		fprintf( myPort "Group prefix: %L\n" prefix )
    		fprintf( myPort "------------------ PROCESSED CELLS --------------------\n" )
    		fprintf( myPort "Found cells ( Library | Cell | Name | Instance count ):\n" )
    		
    		;;; Loop through the lists of the librries, cells and views, and use this information to open the cellviews.
    		;;; Loop through the libraries...
    		foreach( lib libList
    			;;; Loop through the cells in the library that match with a name in the celllist...
    			foreach( cell setof( x ddGetObj( lib )~>cells~>name member( x cellList ) )
    				;;; Loop through the views of the cell that match with a name in the viewlist...
    				foreach( view setof( y ddGetObj( lib cell )~>views~>name member( y viewList ) )
    					;;; At the start, nothing known about the content of a cell, parameter "valid" is set to "nil" to indicate nothing has been found.
    					valid = nil
    					;;; Only proceed if this cellview can be opened...
    					when( setq( cellView FPCOpenCellViewByType( lib cell view nil openViewMode ) )
    						sprintf( detailedInfo "%sCellview opened: %s - %s - %s" dryRunPrintString lib cell view )
    						when( verbose printf( "\n%s" detailedInfo ) )
    						detailedInfoList = append( detailedInfoList list( detailedInfo ) )
    
    						;;; Reset the instance counter for this cellview...
    						instanceCount = 0
    						;;; Now select all instances from the source library...
    						foreach( instance setof( z cellView~>instances equal( z~>libName sourceLib ) )
    							instanceName = instance~>name
    							valid = t
    							totalInstanceCount++
    							instanceCount++
    							
    							sprintf( detailedInfo "%s  Processing instance in cell: %s - %s - %s -> %s" dryRunPrintString lib cell view instanceName )
    							when( verbose printf( "\n%s" detailedInfo ) )
    							detailedInfoList = append( detailedInfoList list( detailedInfo ) )
    							
    							;;; Create the group for this single instance, only this flattened instance will be added to this group.
    							;;; Group-name is a concatination of the prefix as specified by the user and the name of the instance.
    							;;; Since the name of the instance is unique in each cell, no need to create a random number...
    							groupName = strcat( prefix instanceName )
    							unless( dryRunOnly groupID = dbCreateFigGroup( cellView groupName t instance~>xy "R0" ) )
    							sprintf( detailedInfo "%s    Group created: %s" dryRunPrintString groupName )
    							when( verbose printf( "\n%s" detailedInfo ) )
    							detailedInfoList = append( detailedInfoList list( detailedInfo ) )
    							
    							;;;Add the parameters to the group...
    							foreach( pyCellDefault pyCellDefaultList
    								parameterName = nthelem( 1 pyCellDefault )
    								parameterType = nthelem( 2 pyCellDefault )
    								parameterValue = nthelem( 3 pyCellDefault )
    																
    								when( dbSearchPropByName( instance parameterName )
    									parameterValue = dbSearchPropByName( instance parameterName )~>value
    								) ;;; end when
    								
    								unless( dryRunOnly dbCreateProp( groupID parameterName parameterType parameterValue ) )
    								
    								sprintf( detailedInfo "%s      Parameter added: %s -> %L" dryRunPrintString parameterName parameterValue )
    								when( verbose printf( "\n%s" detailedInfo ) )
    								detailedInfoList = append( detailedInfoList list( detailedInfo ) )
    							) ;;; end foreach pyCellDefault
    							
    							;;; This is a work-around till solution found:
    							;;; Flattening an instance inside a group does not work (the resulting shapes will not be part of the group)
    							;;; and after the flattening the selection is gone. My work-around:
    							;;; First, I store the list of shapes of the cellview and flatten the instance which will result in more shapes.
    							;;; Then I filter-out of the new shape list the new shapes and add those to the group.
    							cellViewShapeList = cellView~>shapes
    
    							unless( dryRunOnly dbFlattenInst( instance 2 t nil nil ) )
    							sprintf( detailedInfo "%s    Instance flattened: %s" dryRunPrintString instanceName )
    							when( verbose printf( "\n%s" detailedInfo ) )
    							detailedInfoList = append( detailedInfoList list( detailedInfo ) )
    
    							newCellViewShapeList = cellView~>shapes
    							unless( dryRunOnly
    								foreach( shape setof( newShape newCellViewShapeList !member( newShape cellViewShapeList ) )
    									dbAddFigToFigGroup( groupID shape )
    								) ;;; end foreach shape
    							) ;;; end unless
    							
    							sprintf( detailedInfo "%s    Shapes from flat instance added to group: %s" dryRunPrintString groupName )
    							when( verbose printf( "\n%s" detailedInfo ) )
    							detailedInfoList = append( detailedInfoList list( detailedInfo ) )
    
    						) ;;; end foreach instance
    
    						;;; Save the changes made, if opened in append mode...
    						if( equal( openViewMode "a" )
    						then
    							dbSave( cellView )
    						) ;;; end if openViewMode
    
    						;;; Closing the cellview is not needed but good practice...flatten
    						dbClose( cellView )
    						
    						when( zerop( instanceCount )
    							sprintf( detailedInfo "%s  No instances from %s found: nothing done" dryRunPrintString sourceLib )
    							when( verbose printf( "\n%s" detailedInfo ) )
    							detailedInfoList = append( detailedInfoList list( detailedInfo ) )
    						) ;;; end when
    						
    						sprintf( detailedInfo "%sCellview closed: %s - %s - %s" dryRunPrintString lib cell view )
    						when( verbose printf( "\n%s" detailedInfo ) )
    						detailedInfoList = append( detailedInfoList list( detailedInfo ) )
    					) ;;; end when
    					
    					;;; Update the value of the progressbox...
    					when( FPCProgressBoxBatchJob
    						hiSetProgress( FPCProgressBoxBatchJob viewCount )
    						viewCount++
    					) ;;; end unless
    					
    					;;; Of course, only when a cell contains (the right) instances from the source library, the results must be stored.
    					;;; The parameter "valid" is set when needed, and reset to "nil" for each new cellview.
    					if( valid
    					then
    						cellViewCount++
    						fprintf( myPort "%s | %s | %s | %d\n" lib cell view instanceCount )
    					) ;;; end if valid
    
    				) ;;; end foreach view
    			) ;;; end foreach cell
    		) ;;; end foreach lib
    
    		;;; Make sure that the progressbox reaches 100%...
    		when( FPCProgressBoxBatchJob
    			hiSetProgress( FPCProgressBoxBatchJob viewsToProcess )
    		) ;;; end unless
    					
    		;;; and closing the port...
    		fprintf( myPort "---------------------- SUMMARY ------------------------\n" )
    		fprintf( myPort "cells found: %d\n" cellViewCount )
    		fprintf( myPort "pycells found: %d\n" totalInstanceCount )
    		fprintf( myPort "---------------- DETAILED INFORMATION -----------------\n" )
    		foreach( detailedInfo detailedInfoList
    			fprintf( myPort "%s\n" detailedInfo )
    		) ;;; end foreach
    		fprintf( myPort "-------------------- END OF FILE ----------------------\n" )
    		close( myPort)
    		myPort = nil
    		
    		;;; Opening the output file
    		view( outputFileName nil outputFileName t )
    		
    	) ;;; end let
    ) ;;; end procedure FPCDefineViewList
    ;;;;;;;;;;;;;;;;;;;;;;
    
    ;;;;;;;;;;;;;;;;;;;;;;
    ;;; Function which is a wrapper around dbOpenCellViewByType
    ;;; which suppresses any warnings it produces
    ;;; Original code is from Cadence Support.
    procedure( FPCOpenCellViewByType( @rest args )
    	;;; Define a global variable to store the null port in, to
    	;;; save reopening it next time
     	unless( boundp( 'FPCNullPort ) && openportp( FPCNullPort )
    		FPCNullPort = outfile( "/dev/null" )
    	) ;;; unless
    
    	;;; Be good - force any buffered warning to be displayed - this means
    	;;; we don't swallow any warning unrelated to opening a cellView.
    	;;; This is done by creating a new warning (which we'll swallow in a moment)
    	;;; which forces what is in the buffer to be output.
    	warn("")
    
    	;;; use SKILL's dynamic scoping to redefine woport to send all
    	;;; warnings to /dev/null - and get the final (unprinted) warning
    	;;; with getWarn()
    	let( ( cv ( woport FPCNullPort ) )
    		cv = apply( 'dbOpenCellViewByType args )
    		getWarn()
    		cv
    	) ;;; end let
    ) ;;; end procedure FPCOpenCellViewByType
    ;;;;;;;;;;;;;;;;;;;;;;
    

    Download the file and remove the .txt from the filename (this forum does not allow for uploading of .il files). To open the GUI simply type:

    flattenPycells()

    This will open this GUI:

    Then do the following:

    1. Select the source library for the pcells (this is the library of all pcells you want to flatten, if you have more source libraries, you have to run this script multiple times)
    2. Select all libraries in which you want all pcells to be flattened
    3. Select all cells in which you want all pcells to be flattened
    4. Select all (layout) views in which you want all pcells to be flattened
    5. you might want to change the groupname prefix...

    At first I advise you to enable dry-run mode. That way you can verify your settings (reading the log-file) before actually flattening anything. And just do it with one cell, so you can quickly see what is done.

    If you don't trust this code (which is perfectly fine), I suggest you make a full copy of the library in which the cells are that you want to flatten. Make this copy using Cadence, no Linux copy. And then use this script to test it on this copy. That way, if things are not working as expected, you're not in trouble.

    I just tested the code in Virtuoso 6.1.8, on an unmanaged database. If you have to do this on a managed database, first check-out all cells.

    I hope this helps.

    With kind regards,

    Sjoerd

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • patschouly
    patschouly over 5 years ago in reply to Sheppie

    Sorry for the delay!

    This looks really good, thank you very much for sharing the code! This helps me a lot.

    Kind regards,

    Patrick

    • 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