• 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. Make local procedures to use in pcell code

Stats

  • Locked Locked
  • Replies 8
  • Subscribers 144
  • Views 15387
  • 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

Make local procedures to use in pcell code

RVERP
RVERP over 4 years ago

I want to make local SKILL procedures, so they can be used inside pcell code.

I have made some custom Pcells, that use a set of custom procedures. Is there a way to easily embed these procedures inside the pcell code, so that they can still be used by calling the procedure with it's arguments, but that they only exist inside the Pcell?

  • Cancel
  • mbracht
    mbracht over 4 years ago

    Hi,

    If I get you right you want as set of functions that are private to the code the creates the PCell and in such invisible from outside right?
    Well you you might use the SKILL++ lexical scoping/closure capabilities. Consider the below code:

    (inScheme
       (defun getNmosBuilder ()
         (let ()
           (defun privatFunc1 ()
             (println "I'am Func1"))
           (defun privatFunc2 ()
             (println "I'am Func2"))
           (lambda (@rest args)
             (println "I'am building an nmos and may call private functions")
             (privatFunc1)
             (privatFunc2)))))
    (putd 'nmosBuilder (getNmosBuilder))

    The function getNmosBuilder() returns a function object (the return value of lambda...). That function object runs in a lexical scope where it can see the functions privatFunc1() and privatFunc2() that are invisible from outside. The putd() just associates the function object with the symbol nmosBuilder so as you may call it like a regular function. You may now use nmosBuilder() within pcDefinePCell. The actual  code that creates the PCell needs to be in the lambda() block.
    I have to say that I haven't used this in a PCell but I don't see why it shouldn't work...or so I hope.

    Max

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • AurelBuche
    AurelBuche over 4 years ago in reply to mbracht

    Hi

    You don't actually need to use a builder in this case.
    You could use putd directly in your let closure, or the defglobalfun macro to make the code clearer (which uses putd):

    (inScheme
      (let nil

        (defun privatFunc1 nil
          (println "I'am Func1"))

        (defun privatFunc2 nil
          (println "I'am Func2"))

        (defglobalfun nmosBuilder (@rest _args)
          (println "I'am building an nmos and may call private functions")
          (privatFunc1)
          (privatFunc2)
          )

      );closure
    );skill++

    Cheers,

    Aurel

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Tamsay
    Tamsay over 4 years ago in reply to mbracht

    Hi!

    I tried to implement this idea in Aurel's format, but there were a few extra obstacles along the way, and now I have struck a barrier. I have read quite a lot in the forums and in the manual, but couldn't get it to work. 

    Here is the skeleton of the code, with a brief explanation below it:

    inScheme(

    let( ()

    procedure( generateMosForm()

    let( () ... ;

    Load cell init list

    ; ------------------- ...

    ;load list of pcell candidates

    ; Create fields

    ; -------------

    ...

    ;button exists that generates a pcell using an init file to define some parameters

    ?callback "generateMos(/*value selected from the list*/)" ;option1: error -> generateMos not defined

    ?callback generateMos(/*value selected from the list*/) ;option2: error -> generateMos gets executed immediately, incorrectly

    ; Create form

    ; -----------

    ...

    ; Display form

    ; ------------

    ...

    ) ;let

    ) ;procedure

    procedure( generateMos(/*value selected from the list*/)

    ...

    eval('pcDefinePCell(

    ....

    );pcell

    );eval

    ) ;procedure

    defglobalfun( pcellbuilder (@rest _args) generateMosForm()

    );defglobalfun

    );let

    );skill++

    1. Version: ICS6.1.8.
    2. The file extension is .ils
    3. The idea is to have the generateMosForm available to the public, while generateMos (the core) to remain local, and unchanged when generating the pcell.
    4. First issue that appeared was the fact that the pcDefinePcell function is of lambda type, therefore cannot be used in lexical scoping. Solved by putting it in an eval().
    5. I have tried both procedure and defun to define the local functions, there was no real difference (as expected).
    6. Now the biggest issue is the callback that is inside the Form. I have commented in the code the two approaches I have tried (taken them from examples either here on the forums or manuals). None of the works as intended. I also tried to implement a way to call an function object, but that did not work out either.

    Any help would be appreciated!

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 4 years ago in reply to Tamsay

    Some points:

    1. There's no need to use inScheme around the code if you have a .ils suffix. Code in a .ils file is already using "ils" or "Scheme" semantics, so it's unnecessary to surround it with inScheme. I'd remove it to improve readability.
    2. I'm not quite sure why you declared pcellbuilder as a wrapper global function - you could have directly used globalProc instead of procedure on generateMosForm to make it visible outside of the let. BTW, global functions should really use a sensible prefix to ensure they don't clash with anybody else (the convention is they start with an uppercase prefix since Cadence uses lowercase prefixes).
    3. You're right about pcDefinePCell (it's an nlambda function, not lambda though) - using eval is reasonable here because you are generally not concerned about performance issues as the cost of creating a PCell is much higher than the cost of run-time evaluation.
    4. For your final point, you should use "function object callbacks". There's a section on this in the documentation (in the Introduction chapter of <ICinstDir>/doc/skuiref/skuiref.pdf - search for "function object callbacks" in the PDF). With this you can specify ?callback generateMos - what will then happen is that it passes the function object stored in the lexically scoped local variable which is implicitly created by having a local function called generateMos within the same lexical scope, and then that will be called with whatever arguments are defined for that particular kind of callback (this is covered in the documentation). There's no need to reference the function by name that way - you just need to ensure that your callback function expects the same arguments that will be passed to it by the appropriate hi function.

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Tamsay
    Tamsay over 4 years ago in reply to Andrew Beckett

    Thank you Andrew for the response and advices, they are really valuable!

    With these adjustments the callback started working, now it's just a matter of re-shaping the existing code a little bit, but that should be an easier task.

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • AurelBuche
    AurelBuche over 4 years ago in reply to Tamsay

    Hi,

    Just be careful while using eval in SKILL++

    If you want to be sure what you evaluate remains in the same SKILL++ environment: you should provide (theEnvironment) as a second argument [or at least (schemeTopLevelEnv)] otherwise your eval will be evaluated in SKILL

    Cheers,

    Aurel

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Tamsay
    Tamsay over 4 years ago in reply to AurelBuche

    Hi Aurel, thanks for the heads-up and also for your tips!

    Indeed I came to a halt again because of this environment problem, this time it's about some files that are being loaded inside the private core function just before the pcDefinePcell. It looks like it is being loaded correctly, but all the variables that are defined inside the file are being "forgotten" after the reading has finished. Is there a preferred way of handling files in such cases? 
    I was thinking to maybe keep this part of the code in SKILL, as it worked well before it was transferred to SKILL++ environment. There's also another idea to try and save that information in a list maybe(?). 

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • AurelBuche
    AurelBuche over 4 years ago in reply to Tamsay

    Hi,

    I believe the files you are talking about are loaded in SKILL ? (Except SKILL++ extensions: .ils for instance, all the other files are loaded in SKILL by default)

    The SKILL and SKILL++ have two distinct environments. They only share the functions that will be available in both languages by default whatever the way they are defined (macros, functions, methods, ...)

    To access variables from the other language and its environment you have to use inSkill and inScheme

    (If you want to dig further, you might want to look up the following functions and macros to achieve dynamic scoping from SKILL++: dynamic, dynamicLet and defdynamic)

    Have a nice day

    Aurel

    • 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