It looks like you're new here. If you want to get involved, click one of these buttons!
Hi Matthias,
While thinking about ways to create things like guard rings (i.e. contacts surrounding a cell instance), I thought of using PCells for that. Currently the way we create guard rings is roughly as follows:
bbox
of the "child cell" and calculate the dimensions of two vertical and two horizontal contact PCell variants.Since we learned that PCells can instantiate other PCells (which we use as in the pcell_variant
method), I was wondering if it was possible to create a PCell to implement the same functionality and without having to care about cell instance names and changing parameters and such.
When I ran into problems, I remembered that the layout used to create PCell variants might not be the same as the layout in which the "child cell" exists, which now seems to make any PCells instantiating other non-PCells impossible.
Here is a complete example which (beware!) makes KLayout crash when the inst.bbox
method is called within the CellInstantiatingPCell.produce_impl
call:
##
# Creates a variant of a PCell based on the given parameters.
#
# @param lib_cell_name [String] Name of the PCell, with its library, of which a variant is being made.
# @param params [{various}] Parameters for the PCell in a hash.
# @param layout [RBA::Layout] Layout to which the new PCell variant will be added.
def self.pcell_variant(lib_cell_name, params, layout)
libname, cellname = lib_cell_name.split(".")
# first try to get the pcell from the current layout (see http://klayout.de/forum/comments.php?DiscussionID=404&page=1#Item_7)
pcell_decl = layout.pcell_declaration(cellname)
if pcell_decl.nil? # ...and if it doesn't exist, get the library first.
lib = RBA::Library.library_by_name(libname)
lib || raise("Unknown PCell library '#{libname}'")
# find the pcell within the lib
pcell_decl = lib.layout.pcell_declaration(cellname)
pcell_decl || raise("Unknown PCell '#{cellname}'")
end
unused_params = params.dup
pv_indices = {}
# build a param array from the defaults
pv = pcell_decl.get_parameters.collect do |p|
pv_indices[p.name.to_sym] = pv_indices.size # also record the index for each name
p.default
end
# call coerce_parameters to make sure the parameters are consistent
pv = pcell_decl.coerce_parameters(layout, pv)
# now update, step-by-step, the pv with the given parameters and
# call coerce_parameters for each change to remain consistent
params.each do |k, v|
raise("PCell #{lib_cell_name}: Encountered unsupported parameter #{k}") if !pv_indices.include? k
pv[pv_indices[k]] = v
pv = pcell_decl.coerce_parameters(layout, pv)
end
# create a PCell variant cell
if lib.nil?
pcell_var = layout.add_pcell_variant(pcell_decl.id, pv)
else
pcell_var = layout.add_pcell_variant(lib, pcell_decl.id, pv)
end
end
class CellInstantiatingPCell < RBA::PCellDeclarationHelper
def initialize
super
param(:child_cell_index, TypeInt, "Index of child cell", default: -1)
end
def coerce_parameters_impl
puts "Executing coerce_parameters_impl: #{@param_values}"
end
def produce_impl
begin
puts "#{self}: Executing produce_impl with child_cell_index = #{child_cell_index}"
trans = RBA::Trans::new(0, 0)
inst = cell.insert(RBA::CellInstArray.new(child_cell_index, trans))
layer_idx = layout.layer(RBA::LayerInfo.new(1, 0))
puts "PCell layout: #{layout}"
cell.shapes(layer_idx).insert(inst.bbox.dup)
rescue
abort("#{$!}\n#{$!.backtrace.join("\n")}")
end
end
end
class MyPCellLib < RBA::Library
def initialize(pcell_classes)
pcell_classes.each do |pcell_class|
pcell_obj = pcell_class.new
layout.register_pcell(pcell_class.name.to_str.split(':')[-1], pcell_obj)
end
register(self.class.name.split(':')[-1])
end
end
MyPCellLib.new([CellInstantiatingPCell])
# create a top cell
ly = RBA::Application.instance.main_window.create_layout(1).layout
puts "Top layout: #{ly}"
top_idx = ly.add_cell("top")
# create a child cell with some content
child = ly.cell(ly.add_cell("child"))
layer = RBA::LayerInfo.new(2, 0)
layer_idx = ly.layer(layer)
triangle = [[0, 50], [-20, 0], [20, 0]].collect{|pt| RBA::Point.new(pt[0], pt[1])}
child.shapes(layer_idx).insert(RBA::Polygon.new(triangle))
# create a PCell variant which should instantiate the child
# and draw a box on top of it
cci = child.cell_index
pcv = pcell_variant('MyPCellLib.CellInstantiatingPCell', {child_cell_index: cci}, ly)
trans = RBA::Trans::new(200, 100)
ly.cell(top_idx).insert(RBA::CellInstArray::new(pcv, trans))
lv = RBA::Application.instance.main_window.current_view
lv.select_cell(top_idx, 0)
lv.add_missing_layers
lv.zoom_fit
Is there a way around it such as moving the "child cell" into another library, or is this a more fundamental limitation of the current PCell architecture? While looking through the PCell API, I was wondering why there is a "guiding shapes" interface but nothing similar for "guiding cells" or "guiding instances". The above now seems to be an explanation for this.
Regards, Chris
Comments
Huuuu ... I'm scared!
You like to explore every dark corner of the system, do you? :-)
Not that I don't like being challenged, but I feel a bit like having opened Pandora's box :-)
Basically there is a limitation. Remember that PCell's in libraries are instantiated in the library's local layout. When a layout makes use of a PCell in a library, it will reference that local version through a library proxy, but the PCell is still generated in the library's context. So a cell index is not sufficient to convey the information about the instance. Plus, it is likely to change in a save/load loop, so it's not safe to use cell indexes as parameter values.
A "guiding instance" is not a bad idea. It's surely not easy to implement, but it might be possible.
But it should be possible to script a utility feature that takes the selected instance and wraps a guard ring around it. This ring is just not tied to the cell so whenever the cell is moved, the ring has to be moved with the cell or deleted and generated again.
Matthias
The project I am working on aims at extending KLayout so it could replace some of our company's existing layout generation tools. Therefore I am investigating what can be achieved with the existing API, which leads to experiments such as the one above.
I am aware of that and would not use cell indices anyway - I just wanted to create an example as simple as possible to explain what I was trying to do. In the project itself, we are actually using cell names instead... hoping that they will be more consistent. (Although I am a little bit worried when it comes to PCell variants, as they could also change their names if their parameter values are changed.)
That is what we are using currently. Actually what we have so far is somewhat similar to KLayout's PCells, which made me wonder about using PCells for this in the first place. But until a "guiding cell/instance" will make it into KLayout, we'll stick with what we have.
Just out of curiosity, and only if you have thought about this at all: How would you overcome the problem of the cell/instance not being part of the PCell libraries'
Layout
object?Best regards, Chris
Hi Chris,
Well, I hope I didn't promise too much already :-)
When implementation "guiding instances" I'd not provide a fully functional instance but only some attributes representative for it. For example, a cell bounding box, a transformation (so it's possible to make the PCell act depending on the orientation). So seen from the PCell instantation code a guiding instance won't be a real instance but rather a black box or abstract.
Maybe I'd (optionally) provide the shapes of one (or more) selectable layers too, so you could have access to pins of a macro or an outline layer which is then not just a rectangle. But that scheme will surely be limited to few shapes only.
And you're right: it's not possible to transfer a complete instance into the library's layout. But transferring a cell abstract is.
But as I said, that's surely not easy to implement, so it's not a low-hanging fruit.
Matthias