/* SlottedMetal.il modified from CCSslotMetal.il ; ; adapted to be more user driven by form input. ; now accepts values for slot width, space and length. ; tests for technology snap grid and snaps values to it. ; *****************************************************/ ; ; Define global variables ; ;;************************************************* if(cv = geGetEditCellView() then if(techId = techGetTechFile(cv) then if(techGd = techGetMfgGridResolution(techId) then dbl_techGd = (techGd * 2) else error("Could not obtain technology Grid information") ) ; fi techGd else error("Could not obtain technology Id") ) ; fi techId else error("Could not obtain cell view") ) ; fi cv ;;************************************************* ; ; ORIGINAL CADENCE HEADER ; /******************************************************* Group Custom IC, Cadence Design Systems Language SKILL Revision No. 1.2 Date Created Oct 10, 2005 Last Modified Tested in IC5141, ICOA5251 Lint score 100 (best is 100) Description: A set of procedures to make it easy to generate slotted metal paths. The main procedure is CCSslotMetal() which calls the enterPath function and provides an options form for controling the behaviour of the path generation. The options form has three fields, the path width, the layer on which the path is to be drawn and the snap mode. If the width or snap mode are changed the effect is immediate, the layer is only used when the path points have all been entered. The low-level data creation function uses rodCreatePath to create a multipart path. The master path has an offset path and between them, offset rectangles are created to create the slotted metal structure. Usage: ;; this function can be typed in the CIW CCSslotMetal() ;; or assigned to a bindkey hiSetBindKey("Layout" "Ctrlm" "CCSslotMetal()") NOTE: The Lint score of 100 was achieved after taking account of the global form variable (Package Prefixes = CCSslot on Lint form) *************************************************** SCCS Info: @(#) CCSslotMetal.il 06/19/06.13:10:12 1.2 ******************************************************************** * DISCLAIMER: The following code is provided for Cadence customers * * to use at their own risk. The code may require modification to * * satisfy the requirements of any user. The code and any * * modifications to the code may not be compatible with current or * * future versions of Cadence products. * * THE CODE IS PROVIDED "AS IS" AND WITH NO WARRANTIES, INCLUDING * * WITHOUT LIMITATION ANY EXPRESS WARRANTIES OR IMPLIED WARRANTIES * * OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. * ******************************************************************** */ /******************************************************************** * * * SlottedMetal() * * * * This is the main entry procedure which causes the options form to * * be built and starts the enterPath function with the appropriate * * callback functions set. The enter function forces the options * * form to always be displayed when the command starts * * * ********************************************************************/ procedure(SlottedMetal() let( (form) ;; comment out the if() statement to allow dynamic updating ;; ;; if the Slot Metal options form does not exist then force ;; it to be created, otherwise capture it in a local variable if(boundp('CCSslotMetalForm) && CCSslotMetalForm then form = CCSslotMetalForm else form = CCScreateSlotMetalForm() ); if when(hiIsForm(form) enterPath( ?prompts list("Enter points for slotted metal path") ?form form ?points nil ?doneProc "CCSslotMetalDoneProc" ?addPointProc "CCSslotMetalPoints" ?delPointProc "CCSslotMetalPoints" ?pathWidth form->width->value ?alwaysMap t ?cmdName "SlottedMetal()" ); enterPath ); when the form exists ); let ); procedure SlottedMetal /******************************************************************* * * * CCScreateSlotMetalForm() * * * * The function that creates the Slot Metal options form. The form * * has several fields including: width, snap mode and layer. * * Several of these have callbacks for when they are changed. * * Since this is an options form it does not have a done action; * * that is given by the enter function associated with this options * * form. * * * *******************************************************************/ procedure(CCScreateSlotMetalForm() let( (width layer snap snapModes widemtl slotw slotsp slotl form cv techId) if(cv = geGetEditCellView() then if(techId = techGetTechFile(cv) then ;;************************************************* ;; width is a float number limited only to ;; being larger than wide metal. CCSchangeSlotMetalWidth is ;; called if the width value is changed on the form ;;************************************************* width = hiCreateFloatField( ?name 'width ?prompt "Width" ?value 36.0 ?defValue 36.0 ?callback "CCSchangeSlotMetalWidth()" ); hiCreateFloatField ;;************************************************* ;; widemtl is a float number that is tech dependent. ;; If tech defined, then use a Get() function to load value. ;; It is a minimum value for slotted metal ;; (values less than this do not need slots), ;; therefore a maximum dimension between slots in ;; slotted metal. It must be smaller than bus Width. ;; ChangeWideMetal() is ;; called if widemtl value is changed on the form ;;************************************************* widemtl = hiCreateFloatField( ?name 'widemtl ?prompt "Wide Metal" ?value 35.0 ?defValue 35.0 ?callback "ChangeWideMetal()" ); hiCreateFloatField ;;************************************************* ;; slotw is a float number that is tech dependent. ;; If tech defined, then use a Get() function to load value. ;; It must be greater than or equal to layer min Spacing. ;; ChangeSlotWidth() is ;; called if widemtl value is changed on the form ;;************************************************* slotw = hiCreateFloatField( ?name 'slotw ?prompt "Slot Width" ?value 2.4 ?defValue 2.4 ?callback "ChangeSlotWidth()" ); hiCreateFloatField ;;************************************************* ;; slotsp is a float number that is tech dependent. ;; If tech defined, then use a Get() function to load value. ;; Slotsp defines the min enclosure of slots as well as ;; the minimum spacing between slots. ;; It must be greater than or equal to layer min Width ;; because min layer width could be the thickness of mtl ;; enclosing a slot. ;; ChangeSlotSpace() is ;; called if slotw value is changed on the form ;;************************************************* slotsp = hiCreateFloatField( ?name 'slotsp ?prompt "Slot Space" ?value 9.6 ?defValue 9.6 ?callback "ChangeSlotSpace()" ); hiCreateFloatField ;;************************************************* ;; slotl is a float number that is tech dependent. ;; If tech defined, then use a Get() function to load value. ;; Slotl defines the min length of slots and the min ;; spacing of fill metal subrectangles between slots. ;; It must be greater than or equal to layer min Spacing. ;; ChangeSlotLength() is ;; called if slotl value is changed on the form ;;************************************************* slotl = hiCreateFloatField( ?name 'slotl ?prompt "Slot Length" ;; ?range list(50.0 250.0) ; use a range if you do not want values beyond it ;; ************************************IMPORTANT **************************************** ;; >>>>>>>>>>>>>>>>>> do not set range to upper limit of rule <<<<<<<<<<<<<<<<<<<<< ;; it will be used as a minimum variable (upward) value when generating the slotted metal ;; RANGE not recommended as it maximizes slots towards upper end of range, thus ;; increasing bus resistance with longer runs of widemtl relative to bus width ;; *************************************************************************************** ?value 50.0 ?defValue 50.0 ?callback "ChangeSlotLength()" ; don't need a callback if using a range ; ?callback "" ); hiCreateFloatField ;;**************************************************** ;; the snap mode is a cyclic field with choices that ;; follow the layout editor choices somewhat, the ;; CCSchangeSlotMetalSnap function is called when the ;; snap mode is changed on the form. The initial snap ;; mode is set to the snap mode environment variable ;;**************************************************** snapModes = list("orthogonal" "diagonal" "L90XFirst" "L90YFirst") snap = hiCreateCyclicField( ?name 'snap ?choices snapModes ?prompt "Snap mode" ?value car(member(envGetVal("layout" "snapMode") snapModes)) || "orthogonal" ?callback "CCSchangeSlotMetalSnap()" ); hiCreateCyclicField ;;******************************************************** ;; the layer is a cyclic layer field, it is initially ;; set to the current entry layer and has choices that ;; follow the LSW valid layers. ;; The callback procedure redefines the minLaySp and ;; minLayWid variable values. ;; If the chosen layer has no tech-defined minSp or minWid ;; the slot values will be reset to default. ;;******************************************************** layer = hiCreateLayerCyclicField( techId ; d_techFileId "Layer" ; t_fieldPrompt "caeChangeSlotLayer()" ; t_callback leGetValidLayerList(techId) || list(leGetEntryLayer(techId)) ; l_layers leGetEntryLayer(techId) ; l_LPpair 'layer ; s_fieldName ); hiCreateLayerCyclicField ;;*********************************************************** ;; create a 2-dimensional options form which is always ;; displayed when the function starts. ;;********************************************************** form = hiCreateAppForm( ?name 'CCSslotMetalForm ?formTitle "Slot Metal" ?formType 'options ?buttonLayout 'HideCancelDef ?fields list( list(width 0:0 150:30 80) list(snap 250:0 100:30 70) list(layer 0:30 200:30 80) list(widemtl 0:60 150:30 80) list(slotw 0:90 150:30 80) list(slotl 0:120 150:30 80) list(slotsp 0:150 150:30 80) ) ); hiCreateAppForm ;;********************************************************** ;; ensure that the snap mode reflects the form choice ;; since the default snap mode comes from an environment ;; variable ;;********************************************************** leSetFormSnapMode(form->snap->value) CCSslotMetalForm = form else error("Could not obtain technology information") ); if the technology information can be obtained else error("Slot metal functions require a cellview to be current") ); if a current cellview exists ); let ); procedure CCScreateSlotMetalForm /******************************************************************** * * * CCSchangeSlotMetalWidth() * * * * This function is called when the width is changed. The width is * * adjusted so that it is divisible by three to exactly one decimal * * place. Then the enterFunction is updated to take effect of the * * width change, effectively re-invoked with the points so far which * * are stored on the form by another callback function. * * * ********************************************************************/ procedure(CCSchangeSlotMetalWidth() let( (origWidth currentWidth minLayWid) when(boundp('CCSslotMetalForm) && CCSslotMetalForm minLayWid = GetTechMinLayWidth() origWidth = CCSslotMetalForm->width->defValue currentWidth = CCSslotMetalForm->width->value if(currentWidth <= CCSslotMetalForm->widemtl->value then ; do not allow less than or equal to Wide Metal width currentWidth = CCSslotMetalForm->width->defValue printf("Bus width may not be less than Wide Metal.\n") printf("Resetting width to original value %f.\n" CCSslotMetalForm->width->defValue) printf("First reset Wide Metal smaller if you want a smaller bus width.\n") else if(currentWidth < minLayWid then ; do not allow less than min layer width currentWidth = CCSslotMetalForm->width->defValue printf("Bus width may not be less than min Layer Width rule.\n") printf("Resetting width to original value %f.\n" origWidth) ); fi ); fi ;; make the width divisible by double the grid resolution, ;; this is so that the width dimension will always be on grid ;; at the center of the path and at both edges if(round(currentWidth/dbl_techGd - 1e-9) * dbl_techGd != currentWidth then printf("Bus width must be evenly divisible by twice the minimum tech snap grid.\n") printf("Rounding width down to closest value at twice the snap grid.\n") ) ; fi not on dbl_techGd CCSslotMetalForm->width->value = round(currentWidth/dbl_techGd + 1e-9) * dbl_techGd ;; the following is apparently required to prevent recursion unless(CCSslotMetalForm->currentWidth == CCSslotMetalForm->width->value CCSslotMetalForm->currentWidth = CCSslotMetalForm->width->value ); unless ;; re-invoke enterPath with the new width value and the ;; points so far (stored on the form by another callback) changeEnterFun( 'enterPath ?pathWidth CCSslotMetalForm->width->value ?doneProc "CCSslotMetalDoneProc" ?points CCSslotMetalForm->points ?addPointProc "CCSslotMetalPoints" ?delPointProc "CCSslotMetalPoints" ?prompts list("Enter points for slotted metal path") ?form CCSslotMetalForm ); changeEnterFun ); when the form exists ); let ); procedure CCSchangeSlotMetalWidth /******************************************************************** * * * ChangeWideMetal() * * * * This function is called when wide metal width is changed. * * Wide metal is tested to be less than overall Width, greater than * * min layer width, and greater than slot spacing as defined by the * * form or user. * * The form value is updated if needed. * * * ********************************************************************/ procedure(ChangeWideMetal() let( (form origWidth currentWidth minLayWid) when(boundp('CCSslotMetalForm) && CCSslotMetalForm form = CCSslotMetalForm minLayWid = GetTechMinLayWidth() origWidth = form->widemtl->defValue currentWidth = form->widemtl->value if(currentWidth < minLayWid then ; do not allow less than min layer width CCSslotMetalForm->widemtl->value = origWidth printf("Wide Metal may not be less than min Layer Width rule.\n") printf("Resetting Wide Metal to original value %f\n" origWidth) ); fi if(currentWidth >= form->width->value then ; do not allow greater than or equal to bus Width CCSslotMetalForm->widemtl->value = origWidth printf("Wide Metal must be smaller than bus width. \n") printf("Resetting Wide Metal to original value %f\n" origWidth) printf("First reset bus Width larger if you want a larger Wide Metal value.\n") ); fi if(currentWidth < CCSslotMetalForm->slotsp->value then ; do not allow greater slotsp than wide metal CCSslotMetalForm->widemtl->value = origWidth printf("Wide Metal cannot be smaller than Slot Spacing.\n") printf("Resetting Slot Space to original value %f\n" origWidth) ); fi ;; the following is apparently required to prevent recursion unless(CCSslotMetalForm->currentWideMtl == CCSslotMetalForm->widemtl->value CCSslotMetalForm->currentWideMtl = CCSslotMetalForm->widemtl->value ); unless ); when the form exists ); let ); procedure ChangeWideMetal /******************************************************************** * * * ChangeSlotWidth() * * * * This function is called when slot width is changed. * * The slot width is tested to be greater than min layer spacing. * * The form value is updated if needed. * * * ********************************************************************/ procedure(ChangeSlotWidth() let( (form origWidth currentWidth minLaySp) when(boundp('CCSslotMetalForm) && CCSslotMetalForm form = CCSslotMetalForm minLaySp = GetTechMinLaySpace() origWidth = CCSslotMetalForm->slotw->defValue currentWidth = CCSslotMetalForm->slotw->value if(currentWidth < minLaySp then ; do not allow less than min layer spacing CCSslotMetalForm->slotw->value = origWidth printf("Slot Width may not be less than min Layer Spacing rule.\n") printf("Resetting Slot Width to original value %f\n" origWidth) ); fi ;; the following is apparently required to prevent recursion unless(CCSslotMetalForm->currentSlotw == CCSslotMetalForm->slotw->value CCSslotMetalForm->currentSlotw = CCSslotMetalForm->slotw->value ); unless ); when the form exists ); let ); procedure ChangeSlotWidth /******************************************************************** * * * ChangeSlotSpace() * * * * This function is called when slot spacing is changed. * * The spacing is tested so that it cannot be less than min layer * * width or greater than half of wide metal after removing one * * slot. * * The form value is updated if needed. * * * ********************************************************************/ procedure(ChangeSlotSpace() let( (form origSp currentSp minLayWid) when(boundp('CCSslotMetalForm) && CCSslotMetalForm form = CCSslotMetalForm minLayWid = GetTechMinLayWidth() origSp = CCSslotMetalForm->slotsp->defValue currentSp = CCSslotMetalForm->slotsp->value if(currentSp < minLayWid then ; do not allow less than min layer width CCSslotMetalForm->slotsp->value = origSp printf("Slot Spacing may not be less than min Layer Width rule.\n") printf("Resetting Slot Space to original value %f\n" origSp) ); fi if(currentSp > ((form->widemtl->value - form->slotw->value)/2) then ; do not allow greater than 1/2 wide metal after removal of slot CCSslotMetalForm->slotsp->value = origSp printf("Slot Spacing cannot be greater than half of Wide Metal after removal of a slot width.\n") printf("Resetting Slot Space to original value %f\n" origSp) ); fi ;; the following is apparently required to prevent recursion unless(CCSslotMetalForm->currentSlotsp == CCSslotMetalForm->slotsp->value CCSslotMetalForm->currentSlotsp = CCSslotMetalForm->slotsp->value ); unless ); when the form exists ); let ); procedure ChangeSlotSpace /********************************************************************** * * * ChangeSlotLength() * * * * This function is called when slot length is changed. * * The slot length is tested to be greater than or equal to min layer * * spacing. * * The form value is updated if needed. * * * **********************************************************************/ procedure(ChangeSlotLength() let( (form origLen currentLen minLaySp) when(boundp('CCSslotMetalForm) && CCSslotMetalForm form = CCSslotMetalForm minLaySp = GetTechMinLaySpace() origLen = CCSslotMetalForm->slotl->defValue currentLen = CCSslotMetalForm->slotl->value if(currentLen < minLaySp then ; do not allow less than min layer spacing CCSslotMetalForm->slotl->value = origLen printf("Slot Length may not be less than min Layer Spacing rule.\n") printf("Resetting Slot Length to original value %f\n" origLen) ); fi ;; the following is apparently required to prevent recursion unless(CCSslotMetalForm->currentSlotl == CCSslotMetalForm->slotl->value CCSslotMetalForm->currentSlotl = CCSslotMetalForm->slotl->value ); unless ); when the form exists ); let ); procedure ChangeSlotLength /***************************************************************** * * * CCSchangeSlotMetalSnap() * * * * A callback procedure for the snap mode. When the snap mode is * * changed, the previous value is stored on the form and the snap * * mode is changed to the form selection. * * * *****************************************************************/ procedure(CCSchangeSlotMetalSnap() when(boundp('CCSslotMetalForm) && CCSslotMetalForm CCSslotMetalForm->origSnap = leSetFormSnapMode(CCSslotMetalForm->snap->value) ); when the form exists ); procedure CCSchangeSlotMetalSnap /***************************************************************** * * * caeChangeSlotLayer() * * * * A callback procedure for the layer rules. When the layer is * * changed, the minLayWid and minLaySp values are updated. * * * *****************************************************************/ procedure(caeChangeSlotLayer() let( (form) when(boundp('CCSslotMetalForm) && CCSslotMetalForm form = CCSslotMetalForm GetTechMinLayWidth() GetTechMinLaySpace() ); when the form exists ); let ); procedure caeChangeSlotLayer /******************************************************************** * * * CCSslotMetalPoints(w_win l_points) * * * * A callback procedure to keep track of the points entered, this * * is needed for when the enterFunction is changed due to a change * * in the width value. The points list so far is stored on the form. * * * ********************************************************************/ procedure(CCSslotMetalPoints(win points "wl") when(windowp(win) ;; keep track of the points for when the enterFunction is changed CCSslotMetalForm->points = points ) ); procedure CCSslotMetalPoints /******************************************************************** * * * CCSslotMetalDoneProc(w_win g_done l_points) * * * * A callback procedure for an enter function. The enter function * * provides three arguments, the current window, a flag for whether * * the function was cancelled or not, and the points entered by the * * user. If the enter function was not cancelled, a low-level data * * creation routine is called to actually create the slot metal path * * * ********************************************************************/ procedure(CCSslotMetalDoneProc(win done points "wgl") let( ( form ) when(boundp('CCSslotMetalForm) && CCSslotMetalForm form = CCSslotMetalForm if(done then ;; reset the currentWidth variable stored on the form ;; and reset the points list stored on the form form->currentWidth = nil form->points = nil CCSslotMetalCB( win->cellView form->width->value ; send width value form->widemtl->value ; send wide mtl value form->slotw->value ; send slot width value form->slotl->value ; send slot length value form->slotsp->value ; send slot spacing value CCSgetLPPfromLayerCyclic(form->layer->value) points ) else ;; put back the most recent previous snap mode when(CCSslotMetalForm->origSnap leSetFormSnapMode(CCSslotMetalForm->origSnap) ); when ); if done ); when form exists ); let ); procedure CCSslotMetalDoneProc /**************************************************************************************** * * * CCSslotMetalCB(d_cv f_width f_widemtl f_slotw f_slotl f_slotsp l_layer l_points) * * * * This function calls rodCreatePath to create the multipart * * path based on the width, layer and points values passed in. * * * ****************************************************************************************/ procedure(CCSslotMetalCB(cv width widemtl slotw slotl slotsp layer points "dfffffll") let((pws pww uw testw tpw num_s num_p num_pww num_pws pwsu hpwwu hpwsu init_offset init_pw a_list b_list c_list side count) testw = width + slotw - techGd uw = widemtl + slotw hpwwu = uw/2 pww = widemtl num_s = truncate(testw/uw) num_p = num_s + 1 tpw = width - (num_s * slotw) init_offset = 0 a_list = list() b_list = list() c_list = list() side = 1 count = 0 ;;printf("Test width is %f.\n" testw) ;;printf("Initial number of slots is %x.\n" num_s) ;;printf("Total path width is %f.\n" tpw) ;;printf("Initial number of paths is %x.\n" num_p) ;;******************************************* ;; ;; Define small path width and number of ;; both small and wide paths. ;; There are 4 possible combinations using ;; small paths: ;; (1) no small paths ;; (2) one small path in the center ;; (3) one small path each side of center ;; (4) three small paths, centered ;; With each option there can be any number ;; of wide paths on each side of center. ;; The list build will depend on each option. ;; ;;******************************************* if(tpw > widemtl then ;;printf("Float remainder of tpw and widemtl is %f.\n" GetFloatRemainder(tpw widemtl)) if(abs(tpw - (num_p*widemtl)) < 1e-9 then ; multiple tests for exact num_pww = truncate(tpw/widemtl) pws = 0.0 num_pws = 0 else printf("Bus is not all wide paths.\n") if(GetFloatRemainder(tpw widemtl) >= slotsp && ; remainder is enough for small path mod(truncate(tpw/widemtl) 2) == 0 then ; and even number of wide paths num_pww = truncate(tpw/widemtl) if(num_s == num_pww then num_pws = 1 ; one small path in center pws = GetFloatRemainder(tpw widemtl) ; small path width is remainder else num_pws = 2 ; two small paths in center pws = GetFloatRemainder(tpw widemtl)/2 ; small path width is remainder ) ; fi num_pws else ; remainder is too small num_pww = truncate(tpw/widemtl) - 1 ; subtract one wide path num_pws = 2 ; increase num small paths pws = (GetFloatRemainder(tpw widemtl) + widemtl)/2 ) ; fi ;;printf("Slot spacing is %f.\n" slotsp) ;;printf("GetFloatRemainder(tpw widemtl) is %f.\n" GetFloatRemainder(tpw widemtl)) ;;printf("Num_pww is now %x.\n" num_pww) ;;printf("Num_pws is now %x.\n" num_pws) ;;printf("Small path width is %f.\n" pws) if(mod(num_pww 2) == 1 then ; if there are odd remaining wide paths num_pww = num_pww - 1 ; decrement to make even wide paths num_pws = 3 pws = (GetFloatRemainder(tpw widemtl) + (2 * widemtl))/3 ) ; fi num_pws eq 3 ) ; fi pws eq 0 else num_pww = 0 num_pws = 2 pws = tpw/2 ); fi tpw if(pws != 0.0 then ; make sure small path width is on grid if(abs(GetFloatRemainder(pws dbl_techGd)) < 1e-9 then printf("Small path is on grid.\n") else printf("Small path width is %f.\n" pws) ;;printf("The pws value after the decimal place using GetFloatRemainder is %f.\n" ;; GetFloatRemainder(pws dbl_techGd)) ;;printf("Subtracting the values post dbl tech Grid decimal place.\n") ;;printf("This will round down to the nearest value on dbl the tech grid.\n") pws = round((pws - GetFloatRemainder(pws dbl_techGd))/dbl_techGd + 1e-9) * dbl_techGd printf("Small path width snapped to twice snap grid.\n") printf("Small path width now %f.\n" pws) ; round small path width to grid ) ; fi abs ) ; fi pws not zero ;;printf("Slot spacing is %f.\n" slotsp) ;;printf("Num_pww is %x.\n" num_pww) ;;printf("Num_pws is %x.\n" num_pws) ;;printf("Small path width is %f.\n" pws) ;;******************************************* ;; ;; Confirm number of wide paths to avoid ;; negative values....not sure if this could happen ;; ;;******************************************* if(num_pww < 0 then num_pww = 0 ) ; fi num_pww ;;********************************************* ;; ;; Check the number of paths and slots for ;; accuracy and update them to be correct ;; if needed. This may be necessary if the ;; test width is close to a round number of ;; paths and slots. ;; ;;********************************************* if(num_p > (num_pww + num_pws) || num_p == num_s then num_p = num_pww + num_pws printf("Total number of paths changed to %x.\n" (num_pww + num_pws)) if(num_s = num_p then num_s = num_p - 1 printf("Number of slots changed to %x.\n" num_s) ) ; fi update num_s ) ; fi update num_p ;;********************************************* ;; ;; Define half path width small unit - hpwsu ;; to be used in the list build of paths and ;; slots/rectangles. ;; ;;********************************************* printf("Number of wide paths is %x.\n" num_pww) printf("Number of small paths is %x.\n" num_pws) printf("Number of slots is %x.\n" num_s) printf("Small path width is %f.\n" pws) if(num_pws == 0 then hpwsu = 0.0 pwsu = 0.0 else hpwsu = (pws + slotw)/2 pwsu = (pws + slotw) ) ; fi pws if(num_pww == 0 then hpwwu = 0.0 pwwu = 0.0 else hpwwu = (pww + slotw)/2 pwwu = (pww + slotw) ) ; fi pww ;;printf("Path width small unit is %f.\n" pwsu) ;;printf("Half path width small unit is %f.\n" hpwsu) ;;printf("Path width wide unit is %f.\n" pwwu) ;;printf("Half path width wide unit is %f.\n" hpwwu) ;;******************************************* ;; ;; Confirm total bus width ;; ;;******************************************* new_width = (num_s * slotw) + (num_pww * widemtl) + (num_pws * pws) printf("Final width is %f.\n" new_width) if(new_width != width then printf("New width after adjusting pws is %f.\n" new_width) printf("This compares to original width : %f.\n" width) width = new_width ;; update form so user can see width change CCSslotMetalForm->width->value = width printf(">>>>>>>>>>> BUS WIDTH ADJUSTED <<<<<<<<<<<<<<<<\n") printf("Width = %f\n" width) ) ; fi new_width ;;******************************************* ;; ;; Set initial offset and path width ;; ;;******************************************* if(mod(num_s 2) == 1 then ; slot in center if(pws == 0 then ; no small paths - wide path each side of center init_offset = hpwwu init_pw = pww else ; small paths each side of center init_offset = (pws + slotw)/2 init_pw = pws ) ; fi pws else ; path in center if(pws == 0 then ; no small paths - wide path in center init_pw = pww else ; small path in center init_pw = pws ) ; fi pws ) ; fi mod ;;if(init_offset == 0 then ;; printf("Initial offset path is %x.\n" init_offset) ;; else ;; printf("Initial offset path is %f.\n" init_offset) ;;) ; fi print init_offset ;;********************************************* ;; ;; Build list of small paths. ;; Place into b_list in FILO order. ;; This is independent of and precedes ;; possible combinations with wide paths. ;; ;;********************************************* for(i 0 num_pws-2 ; first path is already placed if(mod(i 2) == 0 then ; if nth even num small path then side = -1 ; right side offset count = count + 1 else ; if nth odd num small path then side = 1 ; left side offset ) ; fi mod a_list= list( ; sublist of small paths ?layer layer ?width pws ?sep side * count * pwsu ;; separation is a multiple of count and small path unit ?choppable t ) b_list = cons(a_list b_list) ; build list ) ; for num_pws ;;********************************************* ;; ;; Build the wide paths depending on the number ;; of small paths. ;; Add to the existing list of small paths. ;; ;;********************************************* count = 0 ; reset count if(num_pws == 0 then ; if there are NO SMALL PATHS for(i 0 num_pww-2 ; build list beginning with 2nd path if(mod(i 2) == 0 then ; if nth even num wide path side = -1 ; right side offset count = count + 1 else ; if nth odd num wide path side = 1 ; left side offset ) ; fi mod a_list= list( ; sublist of wide paths ?layer layer ?width pww ?sep side * count * pwwu ?choppable t ) b_list = cons(a_list b_list) ; add to main list ) ; for num_pww else if(num_pws == 1 then ; if there is ONE centered SMALL PATH for(i 0 num_pww-1 ; build list beginning with 1st path if(mod(i 2) == 0 then ; if nth even num wide path side = -1 ; right side offset count = count + 1 else ; if nth odd num wide path side = 1 ; left side offset ) ; fi mod a_list= list( ; sublist of wide paths ?layer layer ?width pww ?sep side*(hpwwu + hpwsu + (count-1)*pwwu) ?choppable t ) b_list = cons(a_list b_list) ; add to main list ) ; for num_pww else if(num_pws == 2 then ; if there are TWO SMALL PATHS for(i 0 num_pww-1 ; build list beginning with 1st path if(mod(i 2) == 0 then ; if nth even num wide path side = 1 ; left side offset count = count + 1 else side = -1 ; right side offset ) ; fi mod a_list= list( ; sublist of wide paths ?layer layer ?width pww ?sep side*(pwsu - side*hpwsu + hpwwu + (count-1)*pwwu) ?choppable t ) ;;separation = side*(pwsu - side*hpwsu + hpwwu + (count-1)*pwwu) ;;printf("Separation for wide paths with 2 small paths is %f.\n" separation) b_list = cons(a_list b_list) ; add to main list ) ; for num_pww else if(num_pws == 3 then ; if there are THREE centered SMALL PATHS for(i 0 num_pww-1 ; build list beginning with 1st path if(mod(i 2) == 0 then ; if nth even num wide path side = -1 ; right side offset count = count + 1 else side = 1 ; left side offset ) ; fi mod a_list= list( ; sublist of wide paths ?layer layer ?width pww ?sep side*(1.5*pwsu + hpwwu + (count-1)*pwwu) ?choppable t ) b_list = cons(a_list b_list) ) ; for num_pww ) ; fi num_pws 3 ) ; fi num_pws 2 ) ; fi num_pws 1 ) ; fi num_pws 0 b_list = reverse(b_list) ; reverse list for rod call ;;********************************************* ;; ;; Build the initial list of rectangles between ;; small paths. Create c_list for rectangles in ;; the same method as b_list of paths. ;; If there are more slots than number of small ;; paths, then create rectangles on each side of each ;; small path. ;; This simplifies the rectangle creation for ;; wide paths. ;; If there are not more slots than small paths, ;; then the only rectangles needed are between ;; the small paths, so make all the slots. ;; ;;********************************************* count = 0 ; reset count a_list = list() ; reuse a_list by resetting it if(num_pws != 0 then ; if there are small paths, make rects if(num_s > num_pws then ; if more slots than small paths, for(i 0 num_pws ; create slots on each side of small paths if(mod(i 2) == 0 then ; one rectangle per small path side = -1 ; right side offset count = count + 1 else side = 1 ; left side offset ) ; fi mod a_list= list( ; sublist of rectangles ?layer layer ?width slotw ?length widemtl ?space slotl ?sep side*(hpwsu + (count-1)*pwsu) ?beginOffset 0.0 ?endOffset 0.0 ?beginSegOffset slotl ?endSegOffset slotl ?gap "distribute" ) c_list = cons(a_list c_list) ; build initial list of rectangles ) ; for num_pws else ; if fewer slots than small paths for(i 0 num_s-1 ; build as many as num slots if(mod(i 2) == 0 then side = -1 ; right side offset count = count + 1 else side = 1 ; left side offset ) ; fi mod a_list= list( ; sublist of rectangles ?layer layer ?width slotw ?length widemtl ?space slotl ?sep side*(hpwsu + (count-1)*pwsu) ?beginOffset 0.0 ?endOffset 0.0 ?beginSegOffset slotl ?endSegOffset slotl ?gap "distribute" ) c_list = cons(a_list c_list) ; build initial list of rectangles ) ; for num_pws ) ; fi num_s ;;********************************************* ;; ;; Build the rest of the list of rectangles ;; between wide paths if not all slots have been ;; created by the small path algorithm above. ;; Complete the c_list for rectangles in ;; the same method as b_list of paths. ;; ;;********************************************* count = 0 ; reset count if(num_pws == 1 then ; if ONE centered SMALL PATH for(i 0 num_pww-3 ; until last outer 2 wide paths if(mod(i 2) == 0 then side = -1 ; right side offset count = count + 1 else side = 1 ; left side offset ) ; fi mod a_list= list( ; sublist of rectangles ?layer layer ?width slotw ?length widemtl ?space slotl ?sep side*(hpwsu + pwwu + (count-1)*pwwu) ?beginOffset 0.0 ?endOffset 0.0 ?beginSegOffset slotl ?endSegOffset slotl ?gap "distribute" ) c_list = cons(a_list c_list) ; add to list of rectanlges ) ; for num_pww else if(num_pws == 2 then ; if TWO centered SMALL PATHS for(i 0 num_pww-3 ; until last outer 2 wide paths if(mod(i 2) == 0 then side = 1 ; left side offset count = count + 1 else side = -1 ; right side offset ) ; fi mod a_list= list( ; sublist of rectangles ?layer layer ?width slotw ?length widemtl ?space slotl ?sep side*(pwsu - side*hpwsu + pwwu + (count-1)*pwwu) ?beginOffset 0.0 ?endOffset 0.0 ?beginSegOffset slotl ?endSegOffset slotl ?gap "distribute" ) ;;separation = side*(pwsu - side*hpwsu + pwwu + (count-1)*pwwu) ;;printf("Separation of rectangles between wide paths\n") ;;printf("with 2 small paths is %f.\n" separation) c_list = cons(a_list c_list) ; add to list of rectangles ) ; for num_pww-3 else if(num_pws == 3 then ; if THREE centered SMALL PATHS for(i 0 num_pww-3 ; until last outer 2 wide paths if(mod(i 2) == 0 then side = -1 ; right side offset count = count + 1 else side = 1 ; left side offset ) ; fi mod a_list= list( ; sublist of rectangles ?layer layer ?width slotw ?length widemtl ?space slotl ?sep side*(1.5*pwsu + pwwu + (count-1)*pwwu) ?beginOffset 0.0 ?endOffset 0.0 ?beginSegOffset slotl ?endSegOffset slotl ?gap "distribute" ) c_list = cons(a_list c_list) ; add to list of rectangles ) ; for num_pww-3 ) ; fi num_pws eq 3 ) ; fi num_pws eq 2 ) ; fi num_pws eq 1 else ; there are NO SMALL PATHS for(i 0 num_s-1 ; create all between wide paths if(mod(i 2) == 0 then ; one rectangle per wide path side = -1 ; right side offset count = count + 1 else side = 1 ; left side offset ) ; fi mod a_list= list( ; sublist of paths ?layer layer ?width slotw ?length widemtl ?space slotl ?sep side*(hpwwu + (count-1)*pwwu) ?beginOffset 0.0 ?endOffset 0.0 ?beginSegOffset slotl ?endSegOffset slotl ?gap "distribute" ) c_list = cons(a_list c_list) ; add to list of rectangles ) ; for num_pws ) ; fi num_pws c_list = reverse(c_list) ; reverse list for rod ;;********************************************* ;; ;; rodCreatePath builds the slotted bus. ;; ;;********************************************* rodCreatePath( ?cvId cv ?layer layer ?width init_pw ?pts points ?offset init_offset ?offsetSubPath b_list ?subRect c_list ); rodCreatePath ) ; let ); procedure CCSslotMetalCB /**************************************************************** * * * CCSgetLPPfromLayerCyclic(l_layCyc) * * * * A procedure to obtain a list of the layer and purpose (the * * layer-purpose pair) from the item returned by a layer cyclic * * field. The parseString function is used to remove () and to * * build the return list, buildString is used to join the list * * elements, after removal of parentheses, without extra spaces. * * * ****************************************************************/ procedure(CCSgetLPPfromLayerCyclic(layCyc "l") parseString( buildString( parseString(cadddr(layCyc) "()") "" ) ) ); procedure CCSgetLPPfromLayerCyclic /**************************************************************** * * * GetFloatRemainder(f_float1 f_float2) * * * * A procedure to obtain and return the remainder of float1 * * from a division by float2. GetFloatRemainder() uses * * float1 as the numerator, and float2 as denominator. * * This divides float2 into float1 a whole number of times and * * returns the remaining float value from float1. * * * * Use this function unless there is a Cadence equivalent. * * * ****************************************************************/ procedure(GetFloatRemainder( float1 float2 "ff") prog( (_args) return(float1 - (truncate((float1/float2) + 0.000001) * float2)) ) ; prog ) ; proc /**************************************************************** * * * GetTechMinLaySpace() * * * * A procedure to obtain and return the value of the current * * entry layer's minimum defined spacing or use the form's * * default value for the SLOT WIDTH alternatively if no tech * * value is found. * * * ****************************************************************/ procedure(GetTechMinLaySpace() prog( (_args) if(minLaySp = techGetSpacingRule(techId "minSpacing" CCSgetLPPfromLayerCyclic(form->layer->value)) then minLaySp = techGetSpacingRule(techId "minSpacing" CCSgetLPPfromLayerCyclic(form->layer->value)) form->minLaySp = minLaySp printf("minLay Spacing is %f\n" minLaySp) else minLaySp = form->slotw->defValue printf("minLay Spacing is undefined.\n") printf("minLay Spacing being set to Slot default width %f.\n" form->slotw->defValue) form->slotw->value = form->slotw->defValue printf("Resetting Slot Width to default value %f.\n" form->slotw->value) ) ; fi minLaySp return(minLaySp) ) ; prog ) ; procedure GetTechMinLaySpace /**************************************************************** * * * GetTechMinLayWidth() * * * * A procedure to obtain and return the value of the current * * entry layer's minimum defined width or use the form's * * default value for the SLOT SPACING alternatively if no tech * * value is found. * * * ****************************************************************/ procedure(GetTechMinLayWidth() prog( (_args) if(minLayWid = techGetSpacingRule(techId "minWidth" CCSgetLPPfromLayerCyclic(form->layer->value)) then minLayWid = techGetSpacingRule(techId "minWidth" CCSgetLPPfromLayerCyclic(form->layer->value)) form->minLayWid = minLayWid printf("minLay Width is %f.\n" minLayWid) else minLayWid = form->slotsp->defValue printf("minLay Width is undefined.\n") printf("minLay Width being set to Slot spacing %f.\n" form->slotsp->defValue) form->slotsp->value = form->slotsp->defValue printf("Resetting Slot Space to default value %f.\n" form->slotsp->value) ) ; fi minLayWid return(minLayWid) ) ; prog ) ; procedure GetTechMinLayWidth