PCell inside PCell

Hi Matthias,

To test the concept of using PCells inside PCells, I made a PCell test library "TestLib2" with two PCells: "Rectangle" and "RectangleArray", where PCell "Rectangle" is used inside PCell "RectangleArray". The code is attached below. It works well. The only thing I notice is that the PCell "Rectangle" is named TestLib2.Testlib2.Rectangle(...) where I would expect Testlib2.Rectangle(...). Is the code ok? I based it on the circle example found in the documentation.

Thank you in advance!

Kind regards,

Tomas

# Test Library 2

module TestLib2

  include RBA

  # Remove any definition of our classes (this helps when 
  # reexecuting this code after a change has been applied)
  TestLib2.constants.member?(:Rectangle) && remove_const(:Rectangle)
  TestLib2.constants.member?(:RectangleArray) &&  remove_const(:RectangleArray)
  TestLib2.constants.member?(:TestLib2) && remove_const(:TestLib2)

# -------------------------------------------------------------------------------  

  # The PCell declaration for the rectangle
  class Rectangle < PCellDeclarationHelper

    include RBA

    def initialize

      # Important: initialize the super class
      super

      # declare the parameters
      param(:l, TypeLayer, "Layer", :default => LayerInfo::new(1, 0))
      param(:w, TypeDouble, "Width", :default => 1.0)
      param(:h, TypeDouble, "Height", :default => 1.0)

    end

    def display_text_impl
      # Provide a descriptive text for the cell
      "Rectangle(L=#{l.to_s},W=#{'%.3f' % w.to_f},H=#{'%.3f' % h.to_f})"
    end

    def produce_impl

      # This is the main part of the implementation: create the layout

      # create the rectangle
      p1=DPoint.new(-w / 2,-h / 2)
      p2=DPoint.new(-w / 2,h / 2)
      p3=DPoint.new(w / 2,h / 2)
      p4=DPoint.new(w / 2,-h / 2)

      pts=[p1,p2,p3,p4]

      # create the shape
      cell.shapes(l_layer).insert(DPolygon.new(pts))

    end

  end

# -------------------------------------------------------------------------------  

  # The PCell declaration for the rectangle array
  class RectangleArray < PCellDeclarationHelper

    include RBA

    def initialize

      # Important: initialize the super class
      super

      # declare the parameters
      param(:l, TypeLayer, "Layer", :default => LayerInfo::new(1, 0))
      param(:w, TypeDouble, "Width", :default => 20.0)
      param(:h, TypeDouble, "Height", :default => 20.0)
      param(:n, TypeInt, "Number of rectangles", :default => 10)
      param(:p, TypeDouble, "Pitch", :default => 200.0)

    end

    def display_text_impl
      # Provide a descriptive text for the cell
      "RectangleArray(L=#{l.to_s},W=#{'%.3f' % w.to_f},H=#{'%.3f' % h.to_f},N=#{n.to_i},P=#{'%.3f' % p.to_f})"
    end

    def produce_impl

      # This is the main part of the implementation: create the layout

      # find the lib
       lib = RBA::Library.library_by_name("TestLib2")
       lib || raise("Unknown lib 'TestLib2'")

      # find the pcell
       pcell_decl = lib.layout.pcell_declaration("Rectangle")
       pcell_decl || raise("Unknown PCell 'Rectangle'")

       for i in 1..n do

         # set the parameters
         param = { "l" => l, "w" => w*i, "h" => h*i}

         # build a param array using the param hash as a source
         pv = pcell_decl.get_parameters.collect do |p|
         param[p.name] || p.default
         end

         # create a PCell variant cell
         pcell_var = layout.add_pcell_variant(lib, pcell_decl.id, pv)

         # instantiate that cell

         xcoord = p*(i-1)
         ycoord = 0.0

         t = RBA::DTrans::new(DPoint.new(xcoord, ycoord))
         cell.insert(RBA::DCellInstArray::new(pcell_var, t))

       end

    end

  end

# -------------------------------------------------------------------------------  

   # The library where we will put the PCell into 
  class TestLib2 < Library

    def initialize  

      # Set the description
      self.description = "Test Library 2"

      # initialize the database unit (line added ~ default is 0.001):
      layout.dbu = 0.0001

      # Create the PCell declarations
      layout.register_pcell("Rectangle", Rectangle::new)
      layout.register_pcell("RectangleArray", RectangleArray::new)
      # Register us with the name "TestLib2".
      # If a library with that name already existed, it will be replaced then.
      register("TestLib2")

    end

  end 

  # Instantiate and register the library
  TestLib2::new

end

Comments

  • Hi Thomas,

    Thanks for sharing this code. About the name, I'd not worry ... this is a generated "speaking" description and that does not have impact on the functionality.

    If you want to avoid this you can take the PCell directly from the current layout:

    ...
        def produce_impl
    
          # This is the main part of the implementation: create the layout
    
          # find the pcell
           pcell_decl = layout.pcell_declaration("Rectangle")
           pcell_decl || raise("Unknown PCell 'Rectangle'")
    
           for i in 1..n do
    
             # set the parameters
             param = { "l" => l, "w" => w*i, "h" => h*i}
    
             # build a param array using the param hash as a source
             # CHANGED: no "lib" ...
             pv = pcell_decl.get_parameters.collect do |p|
               param[p.name] || p.default
             end
    
             # create a PCell variant cell
             # CHANGED: no "lib" ...
             pcell_var = layout.add_pcell_variant(pcell_decl.id, pv)
    
             # instantiate that cell
    ...
    

    This works because the "layout" object isn't the target layout but the layout object of the library. It's finally mirror into the drawn layout.

    I observed a crash while playing with your original code once after re-executing the script ... so I need to say that embedding PCells in other PCells leads to tricky interactions and debugging is kind of difficult. If you do this, I'd advise not to use the built-in debugger.

    Kind regards,

    Matthias

Sign In or Register to comment.